<!doctype html>
<html class="no-js" lang="en" data-content_root="../../">
  <head><meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="../../genindex.html"><link rel="search" title="Search" href="../../search.html">

    <!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25 -->
        <title>osxphotos.iphoto - osxphotos 0.74.2 documentation</title>
      <link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=d111a655" />
    <link rel="stylesheet" type="text/css" href="../../_static/styles/furo.css?v=580074bf" />
    <link rel="stylesheet" type="text/css" href="../../_static/copybutton.css?v=76b2166b" />
    <link rel="stylesheet" type="text/css" href="../../_static/styles/furo-extensions.css?v=8dab3a3b" />
    
    


<style>
  body {
    --color-code-background: #f2f2f2;
  --color-code-foreground: #1e1e1e;
  
  }
  @media not print {
    body[data-theme="dark"] {
      --color-code-background: #202020;
  --color-code-foreground: #d0d0d0;
  
    }
    @media (prefers-color-scheme: dark) {
      body:not([data-theme="light"]) {
        --color-code-background: #202020;
  --color-code-foreground: #d0d0d0;
  
      }
    }
  }
</style></head>
  <body>
    
    <script>
      document.body.dataset.theme = localStorage.getItem("theme") || "auto";
    </script>
    

<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
  <symbol id="svg-toc" viewBox="0 0 24 24">
    <title>Contents</title>
    <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024">
      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/>
    </svg>
  </symbol>
  <symbol id="svg-menu" viewBox="0 0 24 24">
    <title>Menu</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
      <line x1="3" y1="12" x2="21" y2="12"></line>
      <line x1="3" y1="6" x2="21" y2="6"></line>
      <line x1="3" y1="18" x2="21" y2="18"></line>
    </svg>
  </symbol>
  <symbol id="svg-arrow-right" viewBox="0 0 24 24">
    <title>Expand</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
      <polyline points="9 18 15 12 9 6"></polyline>
    </svg>
  </symbol>
  <symbol id="svg-sun" viewBox="0 0 24 24">
    <title>Light mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
      <circle cx="12" cy="12" r="5"></circle>
      <line x1="12" y1="1" x2="12" y2="3"></line>
      <line x1="12" y1="21" x2="12" y2="23"></line>
      <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
      <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
      <line x1="1" y1="12" x2="3" y2="12"></line>
      <line x1="21" y1="12" x2="23" y2="12"></line>
      <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
      <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
    </svg>
  </symbol>
  <symbol id="svg-moon" viewBox="0 0 24 24">
    <title>Dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
    </svg>
  </symbol>
  <symbol id="svg-sun-with-moon" viewBox="0 0 24 24">
    <title>Auto light/dark, in light mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
      class="icon-custom-derived-from-feather-sun-and-tabler-moon">
      <path style="opacity: 50%" d="M 5.411 14.504 C 5.471 14.504 5.532 14.504 5.591 14.504 C 3.639 16.319 4.383 19.569 6.931 20.352 C 7.693 20.586 8.512 20.551 9.25 20.252 C 8.023 23.207 4.056 23.725 2.11 21.184 C 0.166 18.642 1.702 14.949 4.874 14.536 C 5.051 14.512 5.231 14.5 5.411 14.5 L 5.411 14.504 Z"/>
      <line x1="14.5" y1="3.25" x2="14.5" y2="1.25"/>
      <line x1="14.5" y1="15.85" x2="14.5" y2="17.85"/>
      <line x1="10.044" y1="5.094" x2="8.63" y2="3.68"/>
      <line x1="19" y1="14.05" x2="20.414" y2="15.464"/>
      <line x1="8.2" y1="9.55" x2="6.2" y2="9.55"/>
      <line x1="20.8" y1="9.55" x2="22.8" y2="9.55"/>
      <line x1="10.044" y1="14.006" x2="8.63" y2="15.42"/>
      <line x1="19" y1="5.05" x2="20.414" y2="3.636"/>
      <circle cx="14.5" cy="9.55" r="3.6"/>
    </svg>
  </symbol>
  <symbol id="svg-moon-with-sun" viewBox="0 0 24 24">
    <title>Auto light/dark, in dark mode</title>
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
      class="icon-custom-derived-from-feather-sun-and-tabler-moon">
      <path d="M 8.282 7.007 C 8.385 7.007 8.494 7.007 8.595 7.007 C 5.18 10.184 6.481 15.869 10.942 17.24 C 12.275 17.648 13.706 17.589 15 17.066 C 12.851 22.236 5.91 23.143 2.505 18.696 C -0.897 14.249 1.791 7.786 7.342 7.063 C 7.652 7.021 7.965 7 8.282 7 L 8.282 7.007 Z"/>
      <line style="opacity: 50%" x1="18" y1="3.705" x2="18" y2="2.5"/>
      <line style="opacity: 50%" x1="18" y1="11.295" x2="18" y2="12.5"/>
      <line style="opacity: 50%" x1="15.316" y1="4.816" x2="14.464" y2="3.964"/>
      <line style="opacity: 50%" x1="20.711" y1="10.212" x2="21.563" y2="11.063"/>
      <line style="opacity: 50%" x1="14.205" y1="7.5" x2="13.001" y2="7.5"/>
      <line style="opacity: 50%" x1="21.795" y1="7.5" x2="23" y2="7.5"/>
      <line style="opacity: 50%" x1="15.316" y1="10.184" x2="14.464" y2="11.036"/>
      <line style="opacity: 50%" x1="20.711" y1="4.789" x2="21.563" y2="3.937"/>
      <circle style="opacity: 50%" cx="18" cy="7.5" r="2.169"/>
    </svg>
  </symbol>
  <symbol id="svg-pencil" viewBox="0 0 24 24">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-pencil-code">
      <path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" />
      <path d="M13.5 6.5l4 4" />
      <path d="M20 21l2 -2l-2 -2" />
      <path d="M17 17l-2 2l2 2" />
    </svg>
  </symbol>
  <symbol id="svg-eye" viewBox="0 0 24 24">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-eye-code">
      <path stroke="none" d="M0 0h24v24H0z" fill="none" />
      <path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
      <path
        d="M11.11 17.958c-3.209 -.307 -5.91 -2.293 -8.11 -5.958c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6c-.21 .352 -.427 .688 -.647 1.008" />
      <path d="M20 21l2 -2l-2 -2" />
      <path d="M17 17l-2 2l2 2" />
    </svg>
  </symbol>
</svg>

<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation" aria-label="Toggle site navigation sidebar">
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc" aria-label="Toggle table of contents sidebar">
<label class="overlay sidebar-overlay" for="__navigation"></label>
<label class="overlay toc-overlay" for="__toc"></label>

<a class="skip-to-content muted-link" href="#furo-main-content">Skip to content</a>



<div class="page">
  <header class="mobile-header">
    <div class="header-left">
      <label class="nav-overlay-icon" for="__navigation">
        <span class="icon"><svg><use href="#svg-menu"></use></svg></span>
      </label>
    </div>
    <div class="header-center">
      <a href="../../index.html"><div class="brand">osxphotos 0.74.2 documentation</div></a>
    </div>
    <div class="header-right">
      <div class="theme-toggle-container theme-toggle-header">
        <button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
          <svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
          <svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
          <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
          <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
        </button>
      </div>
      <label class="toc-overlay-icon toc-header-icon no-toc" for="__toc">
        <span class="icon"><svg><use href="#svg-toc"></use></svg></span>
      </label>
    </div>
  </header>
  <aside class="sidebar-drawer">
    <div class="sidebar-container">
      
      <div class="sidebar-sticky"><a class="sidebar-brand" href="../../index.html">
  
  <span class="sidebar-brand-text">osxphotos 0.74.2 documentation</span>
  
</a><form class="sidebar-search-container" method="get" action="../../search.html" role="search">
  <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
  <input type="hidden" name="check_keywords" value="yes">
  <input type="hidden" name="area" value="default">
</form>
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
  <ul>
<li class="toctree-l1"><a class="reference internal" href="../../overview.html">OSXPhotos</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../tutorial.html">OSXPhotos Tutorial</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../cli.html">OSXPhotos Command Line Interface (CLI)</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../template_help.html">OSXPhotos Template System</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../package_overview.html">OSXPhotos Python Package Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../API_README.html">OSXPhotos Python API</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../reference.html">OSXPhotos Python Reference</a></li>
</ul>

</div>
</div>

      </div>
      
    </div>
  </aside>
  <div class="main">
    <div class="content">
      <div class="article-container">
        <a href="#" class="back-to-top muted-link">
          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
            <path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path>
          </svg>
          <span>Back to top</span>
        </a>
        <div class="content-icon-container">
          <div class="theme-toggle-container theme-toggle-content">
            <button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
              <svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
              <svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
              <svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
              <svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
            </button>
          </div>
          <label class="toc-overlay-icon toc-content-icon no-toc" for="__toc">
            <span class="icon"><svg><use href="#svg-toc"></use></svg></span>
          </label>
        </div>
        <article role="main" id="furo-main-content">
          <h1>Source code for osxphotos.iphoto</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;Support for iPhoto libraries</span>

<span class="sd">This code is based on https://github.com/jensb/iphoto2xmp by @jensb</span>
<span class="sd">who kindly gave permission to use the derived code under the MIT license.</span>
<span class="sd">The original iphoto2xmp is licensed under the GPL v3 license.</span>

<span class="sd">The following code largely follows the structure of the original iphoto2xmp code</span>
<span class="sd">with adaptations to convert it to python, break into functions for readability,</span>
<span class="sd">and add additional queries needed by osxphotos.</span>

<span class="sd">The code is not optimized. For example, redundant data is stored in multiple</span>
<span class="sd">data structures and the various database files used by iPhoto are opened &amp; closed</span>
<span class="sd">multiple times as needed. This was a deliberate design choice to make the code</span>
<span class="sd">match the original as closely as possible and to make it easier to follow the</span>
<span class="sd">logic of the original code. I also optimized for implementation speed over execution</span>
<span class="sd">speed. iPhoto has not been supported by Apple since 2015 so the expected use case</span>
<span class="sd">for this code is to convert an iPhoto library to a Photos library or to export the</span>
<span class="sd">iPhoto library. Unlike the rest of the osxphotos code, it is not expected the user</span>
<span class="sd">will be using this code repeatedly.</span>

<span class="sd">The iPhotoDB, iPhotoPhotoInfo, iPhotoAlbumInfo, etc. classes are minimal implementations</span>
<span class="sd">of the corresponding classes in osxphotos and are designed to be drop-in replacements</span>
<span class="sd">for the osxphotos classes.  This was done to minimize changes to the rest of the</span>
<span class="sd">osxphotos codebase. These iPhoto implementations do not implement all the methods</span>
<span class="sd">of the corresponding osxphotos classes, only those needed to export or convert</span>
<span class="sd">an iPhoto library.</span>

<span class="sd">All the iPhoto code is contained in this single file. I didn&#39;t want to mess with creating</span>
<span class="sd">a separate package and dealing with the type-hint hell from circular dependencies as all</span>
<span class="sd">the classes are tightly coupled.</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">__future__</span><span class="w"> </span><span class="kn">import</span> <span class="n">annotations</span>

<span class="kn">import</span><span class="w"> </span><span class="nn">dataclasses</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">datetime</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">functools</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">inspect</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">logging</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">pathlib</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">sqlite3</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">functools</span><span class="w"> </span><span class="kn">import</span> <span class="n">cached_property</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Callable</span><span class="p">,</span> <span class="n">get_type_hints</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">zoneinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">ZoneInfo</span>

<span class="kn">import</span><span class="w"> </span><span class="nn">yaml</span>

<span class="kn">from</span><span class="w"> </span><span class="nn">._constants</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
    <span class="n">_IPHOTO_VERSION</span><span class="p">,</span>
    <span class="n">_UNKNOWN_PERSON</span><span class="p">,</span>
    <span class="n">SIDECAR_EXIFTOOL</span><span class="p">,</span>
    <span class="n">SIDECAR_JSON</span><span class="p">,</span>
    <span class="n">SIDECAR_XMP</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.datetime_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime_has_tz</span><span class="p">,</span> <span class="n">datetime_naive_to_local</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.exiftool</span><span class="w"> </span><span class="kn">import</span> <span class="n">ExifToolCaching</span><span class="p">,</span> <span class="n">get_exiftool_path</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.exifutils</span><span class="w"> </span><span class="kn">import</span> <span class="n">angle_to_exif_orientation</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.exportoptions</span><span class="w"> </span><span class="kn">import</span> <span class="n">ExportOptions</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.personinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">MPRI_Reg_Rect</span><span class="p">,</span> <span class="n">MWG_RS_Area</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.photoexporter</span><span class="w"> </span><span class="kn">import</span> <span class="n">PhotoExporter</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.photoinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">PhotoInfo</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.photoquery</span><span class="w"> </span><span class="kn">import</span> <span class="n">QueryOptions</span><span class="p">,</span> <span class="n">photo_query</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.photos_datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">photos_datetime</span><span class="p">,</span> <span class="n">photos_datetime_local</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.phototemplate</span><span class="w"> </span><span class="kn">import</span> <span class="n">PhotoTemplate</span><span class="p">,</span> <span class="n">RenderOptions</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.platform</span><span class="w"> </span><span class="kn">import</span> <span class="n">is_macos</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.scoreinfo</span><span class="w"> </span><span class="kn">import</span> <span class="n">ScoreInfo</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.sqlite_utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">sqlite_columns</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.unicode</span><span class="w"> </span><span class="kn">import</span> <span class="n">normalize_unicode</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.uti</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_preferred_uti_extension</span><span class="p">,</span> <span class="n">get_uti_for_path</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">.utils</span><span class="w"> </span><span class="kn">import</span> <span class="n">hexdigest</span><span class="p">,</span> <span class="n">noop</span><span class="p">,</span> <span class="n">path_exists</span>

<span class="k">if</span> <span class="n">is_macos</span><span class="p">:</span>
    <span class="kn">from</span><span class="w"> </span><span class="nn">.fingerprint</span><span class="w"> </span><span class="kn">import</span> <span class="n">fingerprint</span>

<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s2">&quot;osxphotos&quot;</span><span class="p">)</span>


<div class="viewcode-block" id="iPhotoDB">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoDB">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoDB</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Read an iPhoto library database; interface matches osxphotos.PhotosDB&quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span>
        <span class="n">dbfile</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
        <span class="n">verbose</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[</span><span class="o">...</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">exiftool</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">rich</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">_skip_searchinfo</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
    <span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Create a new iPhotoDB object.</span>

<span class="sd">        Args:</span>
<span class="sd">            dbfile: specify full path to iPhoto library</span>
<span class="sd">            verbose: optional callable function to use for printing verbose text during processing; if None (default), does not print output.</span>
<span class="sd">            exiftool: optional path to exiftool for methods that require this (e.g. iPhotoPhotoInfo.exiftool); if not provided, will search PATH</span>
<span class="sd">            rich: use rich with verbose output</span>
<span class="sd">            _skip_searchinfo: if True, will not process search data from psi.sqlite; useful for processing standalone Photos.sqlite file</span>

<span class="sd">        Raises:</span>
<span class="sd">            PhotosDBReadError if dbfile is not a valid Photos library.</span>
<span class="sd">            TypeError if verbose is not None and not callable.</span>

<span class="sd">        Note:</span>
<span class="sd">            Unlike PhotosDB, you must specify only the path to the root library in dbfile, not the database file</span>
<span class="sd">            rich is not used with iPhoto</span>
<span class="sd">            _skip_searchinfo is not used with iPhoto</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="p">:</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">dbfile</span><span class="p">)</span><span class="o">.</span><span class="n">absolute</span><span class="p">()</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="k">raise</span> <span class="ne">FileNotFoundError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid iPhoto library path: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
            <span class="k">raise</span> <span class="ne">FileNotFoundError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid iPhoto library path: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_library_path</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="p">)</span>  <span class="c1"># compatibility with PhotosDB</span>

        <span class="c1"># for compatibility with PhotosDB but not a 1:1 mapping as iPhoto uses several databases</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">db_path</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">))</span>

        <span class="k">if</span> <span class="n">verbose</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="n">verbose</span> <span class="o">=</span> <span class="n">noop</span>
        <span class="k">elif</span> <span class="ow">not</span> <span class="nb">callable</span><span class="p">(</span><span class="n">verbose</span><span class="p">):</span>
            <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;verbose must be callable&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span> <span class="o">=</span> <span class="n">verbose</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span>  <span class="c1"># compatibility with PhotosDB</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_rich</span> <span class="o">=</span> <span class="n">rich</span>  <span class="c1"># currently unused, compatibility with PhotosDB</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_exiftool_path</span> <span class="o">=</span> <span class="n">exiftool</span>

        <span class="c1"># initialize database dictionaries</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of uuid to photo data</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_dbphotos</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span>  <span class="c1"># for compatability with PhotosDB</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_event_notes</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of modelId to event notes</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_places</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of modelId to places</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_properties</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of versionId to properties</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_exif_info</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of versionId to EXIF info</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_persons</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of modelId to persons</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_faces</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of modelID to face info</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_faces_edited</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of modelID to face info for edited photos</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of modelId to folders</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_albums</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of modelId to albums</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_volumes</span> <span class="o">=</span> <span class="p">{}</span>  <span class="c1"># mapping of volume uuid to volume name</span>

        <span class="c1"># set _db_version, _photos_ver, _model_ver even though they&#39;re not used in iPhoto because other code depends on these</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db_version</span> <span class="o">=</span> <span class="n">_IPHOTO_VERSION</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_photos_ver</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_model_ver</span> <span class="o">=</span> <span class="mi">0</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_load_library</span><span class="p">()</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">_source</span> <span class="o">=</span> <span class="s2">&quot;iPhoto&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_library</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load iPhoto library&quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Loading iPhoto library: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_library_db</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_properties_db</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_persons</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_face_info</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_edited_face_info</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_folders</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_albums</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_keywords</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_image_proxies</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_load_volumes</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_build_photo_paths</span><span class="p">()</span>

        <span class="c1"># logger.debug(f&quot;{self._db_photos=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_event_notes=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_places=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_properties=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_exif_info=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_persons=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_faces=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_faces_edited=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_folders=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_albums=}&quot;)</span>
        <span class="c1"># logger.debug(f&quot;{self._db_volumes=}&quot;)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_library_db</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load the Library.apdb database&quot;&quot;&quot;</span>

        <span class="n">library_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">)</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">library_db</span><span class="p">)</span>
        <span class="n">rkfolder_columns</span> <span class="o">=</span> <span class="n">sqlite_columns</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="s2">&quot;RKFolder&quot;</span><span class="p">)</span>
        <span class="n">rkmaster_columns</span> <span class="o">=</span> <span class="n">sqlite_columns</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="s2">&quot;RKMaster&quot;</span><span class="p">)</span>

        <span class="n">query</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2">        SELECT</span>
<span class="s2">        RKVersion.modelId AS id,</span>
<span class="s2">        RKVersion.masterId AS master_id,</span>
<span class="s2">        RKVersion.name AS title,</span>
<span class="s2">        RKFolder.name AS rollname,</span>
<span class="s2">        RKFolder.modelId AS roll,</span>
<span class="s2">        RKFolder.minImageDate AS roll_min_image_date,</span>
<span class="s2">        RKFolder.maxImageDate AS roll_max_image_date,</span>
<span class="s2">        </span><span class="si">{</span><span class="s2">&quot;RKFolder.minImageTimeZoneName&quot;</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="s2">&quot;minImageTimeZoneName&quot;</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">rkfolder_columns</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s2">&quot;NULL&quot;</span><span class="si">}</span><span class="s2"> AS roll_min_image_tz,</span>
<span class="s2">        </span><span class="si">{</span><span class="s2">&quot;RKFolder.maxImageTimeZoneName&quot;</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="s2">&quot;maxImageTimeZoneName&quot;</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">rkfolder_columns</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s2">&quot;NULL&quot;</span><span class="si">}</span><span class="s2"> AS roll_max_image_tz,</span>
<span class="s2">        RKFolder.posterVersionUuid AS poster_version_uuid,</span>
<span class="s2">        -- event thumbnail image uuid</span>
<span class="s2">        RKFolder.createDate AS date_foldercreation,</span>
<span class="s2">        -- is this the &#39;imported as&#39; date?</span>
<span class="s2">        RKVersion.uuid AS uuid,</span>
<span class="s2">        RKMaster.uuid AS master_uuid,</span>
<span class="s2">        -- master (unedited) image. Required for face rectangle conversion.</span>
<span class="s2">        -- RKVersion.versionNumber AS version_number,</span>
<span class="s2">        -- 1 if edited image, 0 if original image</span>
<span class="s2">        RKVersion.mainRating AS rating,</span>
<span class="s2">        -- TODO: Rating is always applied to the master image, not the edited one</span>
<span class="s2">        RKMaster.type AS mediatype, -- IMGT, VIDT</span>
<span class="s2">        RKMaster.imagePath AS imagepath,</span>
<span class="s2">        -- 2015/04/27/20150427-123456/FOO.RW2, yields Masters/$imagepath and</span>
<span class="s2">        -- Previews: either Previews/$imagepath/ or dirname($imagepath)/$uuid/basename($imagepath)</span>
<span class="s2">        -- ,RKVersion.createDate AS date_imported</span>
<span class="s2">        RKMaster.createDate AS date_imported,</span>
<span class="s2">        RKVersion.imageDate AS date_taken,</span>
<span class="s2">        -- ,RKMaster.imageDate AS datem</span>
<span class="s2">        RKVersion.exportImageChangeDate AS date_modified,</span>
<span class="s2">        -- ,RKMaster.fileCreationDate AS date_filecreation -- is this the &#39;date imported&#39;? No</span>
<span class="s2">        -- ,RKMaster.fileModificationDate AS date_filemod</span>
<span class="s2">        -- ,replace(RKImportGroup.name, &#39; @ &#39;, &#39;T&#39;) AS date_importgroup -- contains datestamp of import procedure for a group of files,</span>
<span class="s2">        -- but this is apparently incorrect for images before 2012 -&gt; ignore</span>
<span class="s2">        RKVersion.imageTimeZoneName AS timezone,</span>
<span class="s2">        RKVersion.exifLatitude AS latitude,</span>
<span class="s2">        RKVersion.exifLongitude AS longitude,</span>
<span class="s2">        RKVersion.isHidden AS hidden,</span>
<span class="s2">        RKVersion.isFlagged AS flagged,</span>
<span class="s2">        RKVersion.isOriginal AS original,</span>
<span class="s2">        RKMaster.isInTrash AS in_trash,</span>
<span class="s2">        RKVersion.masterHeight AS master_height,</span>
<span class="s2">        -- Height of original image (master)</span>
<span class="s2">        RKVersion.masterWidth AS master_width,</span>
<span class="s2">        -- Width of original image (master)</span>
<span class="s2">        RKVersion.processedHeight AS processed_height,</span>
<span class="s2">        -- Height of processed (eg. cropped, rotated) image</span>
<span class="s2">        RKVersion.processedWidth AS processed_width,</span>
<span class="s2">        -- Width of processed (eg. cropped, rotated) image</span>
<span class="s2">        RKVersion.overridePlaceId AS place_id,</span>
<span class="s2">        -- modelId of Properties::RKPlace</span>
<span class="s2">        RKVersion.faceDetectionRotationFromMaster AS face_rotation,</span>
<span class="s2">        -- don&#39;t know, maybe a hint for face detection algorithm</span>
<span class="s2">        RKVersion.rotation AS rotation, -- was the original image rotated?</span>
<span class="s2">        RKVersion.hasAdjustments as hasadjustments,</span>
<span class="s2">        RKVersion.fileName as filename,</span>
<span class="s2">        RKMaster.fileVolumeUuid AS volume_uuid,</span>
<span class="s2">        RKMaster.isMissing AS ismissing,</span>
<span class="s2">        RKMaster.isTrulyRaw AS truly_raw,</span>
<span class="s2">        RKMaster.fileIsReference AS is_reference,</span>
<span class="s2">        RKMaster.originalFileSize as original_filesize,</span>
<span class="s2">        </span><span class="si">{</span><span class="s2">&quot;RKMaster.burstUuid&quot;</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="s2">&quot;burstUuid&quot;</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">rkmaster_columns</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s2">&quot;NULL&quot;</span><span class="si">}</span><span class="s2"> as burst_uuid</span>
<span class="s2">        FROM RKVersion</span>
<span class="s2">        LEFT JOIN RKFolder ON RKVersion.projectUuid = RKFolder.uuid</span>
<span class="s2">        LEFT JOIN RKMaster ON RKMaster.uuid = RKVersion.masterUuid</span>
<span class="s2">        LEFT JOIN RKImportGroup ON RKMaster.importGroupUuid = RKImportGroup.uuid</span>
<span class="s2">        WHERE RKVersion.versionNumber = 1</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>

        <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">:</span>
            <span class="c1"># normalize unicode</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;title&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
            <span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;rollname&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;rollname&quot;</span><span class="p">]</span>
            <span class="p">)</span>
            <span class="c1"># init preview_path (will be loaded by _load_image_proxies)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;preview_path&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Loaded </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">)</span><span class="si">}</span><span class="s2"> assets from iPhoto library&quot;</span><span class="p">)</span>

        <span class="c1"># Event notes (pre-iPhoto 9.1)</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKNote.modelId AS modelId,</span>
<span class="s2">            RKNote.note AS note,</span>
<span class="s2">            RKFolder.name AS name,</span>
<span class="s2">            RKFolder.uuid AS folder_uuid,</span>
<span class="s2">            RKFolder.modelId AS folder_model_id</span>
<span class="s2">            FROM RKNote</span>
<span class="s2">            LEFT JOIN RKFolder on RKNote.attachedToUuid = RKFolder.uuid</span>
<span class="s2">            WHERE RKFolder.name IS NOT NULL AND RKFolder.name != &#39;&#39;</span>
<span class="s2">            ORDER BY RKFolder.modelId</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading event notes from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="n">row</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
            <span class="n">row</span><span class="p">[</span><span class="s2">&quot;note&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;note&quot;</span><span class="p">])</span>
            <span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_event_notes</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;folder_model_id&quot;</span><span class="p">])]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_properties_db</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load the Properties.apdb database&quot;&quot;&quot;</span>
        <span class="n">properties_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Properties.apdb&quot;</span><span class="p">)</span>

        <span class="c1"># Places</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKPlace.modelId,</span>
<span class="s2">            RKPlace.uuid,</span>
<span class="s2">            RKPlace.defaultName,</span>
<span class="s2">            RKPlace.minLatitude,</span>
<span class="s2">            RKPlace.minLongitude,</span>
<span class="s2">            RKPlace.maxLatitude,</span>
<span class="s2">            RKPlace.maxLongitude,</span>
<span class="s2">            RKPlace.centroid,</span>
<span class="s2">            RKPlace.userDefined</span>
<span class="s2">            FROM RKPlace</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">properties_db</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading places from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_places</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;modelId&quot;</span><span class="p">])]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>

        <span class="c1"># normalize unicode</span>
        <span class="k">for</span> <span class="n">model_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_places</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_places</span><span class="p">[</span><span class="n">model_id</span><span class="p">][</span><span class="s2">&quot;defaultName&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_places</span><span class="p">[</span><span class="n">model_id</span><span class="p">][</span><span class="s2">&quot;defaultName&quot;</span><span class="p">]</span>
            <span class="p">)</span>

        <span class="c1"># Properties</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKIptcProperty.modelId AS id,</span>
<span class="s2">            RKIptcProperty.versionId AS versionId,</span>
<span class="s2">            RKIptcProperty.modDate AS modDate,</span>
<span class="s2">            RKUniqueString.stringProperty AS string</span>
<span class="s2">            FROM RKIptcProperty</span>
<span class="s2">            LEFT JOIN RKUniqueString ON RKIptcProperty.stringId = RKUniqueString.modelId</span>
<span class="s2">            WHERE RKIptcProperty.propertyKey = &#39;Caption/Abstract&#39; -- description</span>
<span class="s2">            ORDER BY versionId</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading properties from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="n">row</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
            <span class="n">row</span><span class="p">[</span><span class="s2">&quot;string&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;string&quot;</span><span class="p">])</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_properties</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;versionId&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>

        <span class="c1"># put description back into _db_photos</span>
        <span class="c1"># mapping of versionId -&gt; RKVersion.modelID -&gt; uuid</span>
        <span class="n">version_id_to_uuid</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="n">version_id</span> <span class="o">=</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">version_id</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">version_id_to_uuid</span><span class="p">:</span>
                <span class="n">version_id_to_uuid</span><span class="p">[</span><span class="n">version_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">uuid</span>

        <span class="k">for</span> <span class="n">version_id</span><span class="p">,</span> <span class="n">data</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_properties</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="o">:=</span> <span class="n">version_id_to_uuid</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">version_id</span><span class="p">):</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;description&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">&quot;string&quot;</span><span class="p">]</span>

        <span class="c1"># orientation</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKOtherProperty.versionId AS version_id,</span>
<span class="s2">            RKUniqueString.stringProperty AS str</span>
<span class="s2">            FROM RKOtherProperty</span>
<span class="s2">            LEFT JOIN RKUniqueString ON RKUniqueString.modelId = RKOtherProperty.stringId</span>
<span class="s2">            WHERE RKOtherProperty.propertyKey = &#39;Orientation&#39;</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading orientation from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="o">:=</span> <span class="n">version_id_to_uuid</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;version_id&quot;</span><span class="p">]):</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;orientation&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;str&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>

        <span class="c1"># EXIF Properties</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKExifStringProperty.versionId as versionId,</span>
<span class="s2">            RKExifStringProperty.propertyKey AS property,</span>
<span class="s2">            RKUniqueString.stringProperty AS value</span>
<span class="s2">            FROM RKExifStringProperty</span>
<span class="s2">            INNER JOIN RKUniqueString ON RKUniqueString.modelId = RKExifStringProperty.stringId</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading EXIF properties from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="n">row</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
            <span class="n">row</span><span class="p">[</span><span class="s2">&quot;value&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;value&quot;</span><span class="p">])</span>
            <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;versionId&quot;</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_exif_info</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_exif_info</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;versionId&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_exif_info</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;versionId&quot;</span><span class="p">]][</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;property&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;value&quot;</span><span class="p">]</span>

        <span class="c1"># EXIF data is stored separately whether string or numerical</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKExifNumberProperty.versionId AS versionId,</span>
<span class="s2">            RKExifNumberProperty.propertyKey AS property,</span>
<span class="s2">            RKExifNumberProperty.numberProperty AS value</span>
<span class="s2">            FROM RKExifNumberProperty</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="n">row</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
            <span class="k">if</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;versionId&quot;</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_exif_info</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_exif_info</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;versionId&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_exif_info</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;versionId&quot;</span><span class="p">]][</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;property&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;value&quot;</span><span class="p">]</span>

        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_persons</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load persons from Faces.db database&quot;&quot;&quot;</span>

        <span class="n">faces_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Faces.db&quot;</span><span class="p">)</span>

        <span class="c1"># Faces</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            modelId,</span>
<span class="s2">            uuid,</span>
<span class="s2">            faceKey as face_key,</span>
<span class="s2">            name,</span>
<span class="s2">            email</span>
<span class="s2">            FROM RKFaceName</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">faces_db</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading faces from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_persons</span><span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;modelId&quot;</span><span class="p">])]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_face_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">dict</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load face info for each photo from database&quot;&quot;&quot;</span>

        <span class="n">face_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Faces.db&quot;</span><span class="p">)</span>

        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKDetectedFace.modelId, -- primary key</span>
<span class="s2">            RKDetectedFace.uuid AS detect_uuid, -- primary key</span>
<span class="s2">            RKDetectedFace.masterUuid, -- --&gt; Library::RKMaster::uuid</span>
<span class="s2">            RKDetectedFace.faceKey AS face_key, -- --&gt; RKFaceName::faceKey</span>
<span class="s2">            -- *relative* coordinates within *original, non-rotated* image (0..1)</span>
<span class="s2">            -- Y values are counted from the bottom in iPhoto, but X values are counted from the left like usual!</span>
<span class="s2">            RKDetectedFace.topLeftX,</span>
<span class="s2">            1 - RKDetectedFace.topLeftY AS topLeftY,</span>
<span class="s2">            RKDetectedFace.topRightX,</span>
<span class="s2">            1 - RKDetectedFace.topRightY AS topRightY,</span>
<span class="s2">            RKDetectedFace.bottomLeftX,</span>
<span class="s2">            1 - RKDetectedFace.bottomLeftY AS bottomLeftY,</span>
<span class="s2">            RKDetectedFace.bottomRightX,</span>
<span class="s2">            1 - RKDetectedFace.bottomRightY AS bottomRightY,</span>
<span class="s2">            abs(</span>
<span class="s2">                RKDetectedFace.topLeftX - RKDetectedFace.bottomRightX</span>
<span class="s2">            ) AS width,</span>
<span class="s2">            abs(</span>
<span class="s2">                RKDetectedFace.topLeftY - RKDetectedFace.bottomRightY</span>
<span class="s2">            ) AS height,</span>
<span class="s2">            RKDetectedFace.width AS image_width, -- TODO: check whether face was meant to be rotated?</span>
<span class="s2">            RKDetectedFace.height AS image_height,</span>
<span class="s2">            RKDetectedFace.faceDirectionAngle AS face_dir_angle,</span>
<span class="s2">            RKDetectedFace.faceAngle AS face_angle, -- always 0?</span>
<span class="s2">            RKDetectedFace.confidence AS confidence,</span>
<span class="s2">            RKDetectedFace.rejected AS rejected,</span>
<span class="s2">            RKDetectedFace.ignore AS ignore,</span>
<span class="s2">            RKFaceName.uuid AS name_uuid,</span>
<span class="s2">            RKFaceName.name AS name, -- more reliable, also seems to contain manually added names</span>
<span class="s2">            RKFaceName.fullName AS full_name, -- might be empty if person is not listed in user&#39;s address book</span>
<span class="s2">            RKFaceName.email AS email</span>
<span class="s2">            FROM RKDetectedFace</span>
<span class="s2">            LEFT JOIN RKFaceName ON RKFaceName.faceKey = RKDetectedFace.faceKey</span>
<span class="s2">            WHERE RKDetectedFace.masterUuid = ? -- master_uuid</span>
<span class="s2">            AND RKDetectedFace.ignore = 0</span>
<span class="s2">            AND RKDetectedFace.rejected = 0</span>
<span class="s2">            -- ORDER BY RKDetectedFace.modelId</span>
<span class="s2">    &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">face_db</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading face info from iPhoto library&quot;</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="n">master_uuid</span> <span class="o">=</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;master_uuid&quot;</span><span class="p">]</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="p">(</span><span class="n">master_uuid</span><span class="p">,))</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;faces&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
                <span class="n">row</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
                <span class="c1"># normalize unicode</span>
                <span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
                <span class="n">row</span><span class="p">[</span><span class="s2">&quot;full_name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;full_name&quot;</span><span class="p">])</span>
                <span class="n">row</span><span class="p">[</span><span class="s2">&quot;email&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;email&quot;</span><span class="p">])</span>
                <span class="c1"># assign to library data for matching uuid</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;faces&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_faces</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;modelId&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">row</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_edited_face_info</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load edited face info for each photo from database&quot;&quot;&quot;</span>

        <span class="n">library_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">)</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">library_db</span><span class="p">)</span>

        <span class="c1"># get edited face info</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKVersionFaceContent.modelId AS id,</span>
<span class="s2">            RKVersionFaceContent.versionId AS version_id,</span>
<span class="s2">            RKVersionFaceContent.masterId AS master_id,</span>
<span class="s2">            RKVersionFaceContent.faceKey AS face_key,</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="s2">&quot;faceRectLeft&quot;</span> <span class="ow">in</span> <span class="n">sqlite_columns</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="s2">&quot;RKVersionFaceContent&quot;</span><span class="p">):</span>
            <span class="n">query</span> <span class="o">+=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            RKVersionFaceContent.faceRectLeft AS topLeftX, -- use same naming scheme as in &#39;faces&#39;</span>
<span class="s2">            1 - RKVersionFaceContent.faceRectTop AS bottomRightY, -- Y values are counted from the bottom in this table!</span>
<span class="s2">            RKVersionFaceContent.faceRectWidth AS width,</span>
<span class="s2">            RKVersionFaceContent.faceRectHeight AS height,</span>
<span class="s2">            RKVersionFaceContent.faceRectWidth + RKVersionFaceContent.faceRectLeft AS bottomRightX,</span>
<span class="s2">            1 - RKVersionFaceContent.faceRectTop - RKVersionFaceContent.faceRectHeight AS topLeftY</span>
<span class="s2">            &quot;&quot;&quot;</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">query</span> <span class="o">+=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            0 as topLeftX,</span>
<span class="s2">            0 as bottomRightY,</span>
<span class="s2">            0 as width,</span>
<span class="s2">            0 as height,</span>
<span class="s2">            0 as bottomRightX,</span>
<span class="s2">            0 as topLeftY</span>
<span class="s2">            &quot;&quot;&quot;</span>
        <span class="n">query</span> <span class="o">+=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            FROM RKVersionFaceContent</span>
<span class="s2">            WHERE RKVersionFaceContent.versionId = ? -- id of the photo</span>
<span class="s2">            ORDER BY RKVersionFaceContent.versionId</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading edited face info from iPhoto library&quot;</span><span class="p">)</span>
        <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="n">version_id</span> <span class="o">=</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]</span>
            <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="p">(</span><span class="n">version_id</span><span class="p">,))</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
            <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;edited_faces&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
                <span class="n">row</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
                <span class="n">row</span><span class="p">[</span><span class="s2">&quot;confidence&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                    <span class="mf">0.0</span>  <span class="c1"># TODO: figure out original face and use those values</span>
                <span class="p">)</span>
                <span class="n">face_key</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]</span>
                <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_persons</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
                    <span class="k">if</span> <span class="n">face_key</span> <span class="o">==</span> <span class="n">person</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]:</span>
                        <span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
                        <span class="n">row</span><span class="p">[</span><span class="s2">&quot;email&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">person</span><span class="p">[</span><span class="s2">&quot;email&quot;</span><span class="p">]</span>
                        <span class="n">row</span><span class="p">[</span><span class="s2">&quot;full_name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
                        <span class="k">break</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
                    <span class="n">row</span><span class="p">[</span><span class="s2">&quot;full_name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
                    <span class="n">row</span><span class="p">[</span><span class="s2">&quot;email&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
                <span class="c1"># assign to library data for matching uuid</span>
                <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;edited_faces&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_faces_edited</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">row</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_folders</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load folders from iPhoto library&quot;&quot;&quot;</span>
        <span class="c1"># Get Folders and Albums. Convert to (hierarchical) keywords since &quot;Albums&quot; are nothing but tag collections.</span>
        <span class="c1"># Also get search criteria for &quot;smart albums&quot;. Save into text file (for lack of better solution).</span>
        <span class="c1"># 1. Get folder structure, create tag pathnames as strings.</span>
        <span class="c1">#    Folders are just a pseudo hierarchy and can contain Albums and Smart Albums.</span>

        <span class="n">library_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">)</span>
        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">library_db</span><span class="p">)</span>
        <span class="n">rkfolder_columns</span> <span class="o">=</span> <span class="n">sqlite_columns</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="s2">&quot;RKFolder&quot;</span><span class="p">)</span>

        <span class="n">query</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            modelId,</span>
<span class="s2">            uuid,</span>
<span class="s2">            folderType,</span>
<span class="s2">            name,</span>
<span class="s2">            parentFolderUuid,</span>
<span class="s2">            folderPath,</span>
<span class="s2">            isMagic,</span>
<span class="s2">            createDate as date,</span>
<span class="s2">            minImageDate AS min_image_date,</span>
<span class="s2">            maxImageDate AS max_image_date,</span>
<span class="s2">            </span><span class="si">{</span><span class="s2">&quot;minImageTimeZoneName&quot;</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="s2">&quot;minImageTimeZoneName&quot;</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">rkfolder_columns</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s2">&quot;NULL&quot;</span><span class="si">}</span><span class="s2"> AS min_image_tz,</span>
<span class="s2">            </span><span class="si">{</span><span class="s2">&quot;maxImageTimeZoneName&quot;</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="s2">&quot;maxImageTimeZoneName&quot;</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">rkfolder_columns</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="s2">&quot;NULL&quot;</span><span class="si">}</span><span class="s2"> AS max_image_tz</span>
<span class="s2">            FROM RKFolder</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading folders from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;modelID&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>

        <span class="c1"># normalize unicode</span>
        <span class="k">for</span> <span class="n">model_id</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">model_id</span><span class="p">][</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">model_id</span><span class="p">][</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
            <span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">model_id</span><span class="p">][</span><span class="s2">&quot;folderPath&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">model_id</span><span class="p">][</span><span class="s2">&quot;folderPath&quot;</span><span class="p">]</span>
            <span class="p">)</span>

        <span class="c1"># folderPath is a string like &quot;modelId1/modelId2/...&quot;.</span>
        <span class="c1"># convert these using the real folder names to get the path strings.</span>
        <span class="c1"># the top level libray folder is always modelId 1 and has name &#39;&#39;</span>
        <span class="k">for</span> <span class="n">model_id</span><span class="p">,</span> <span class="n">folder_data</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="n">folder_list</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="k">for</span> <span class="n">folder_id</span> <span class="ow">in</span> <span class="n">folder_data</span><span class="p">[</span><span class="s2">&quot;folderPath&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">):</span>
                <span class="k">if</span> <span class="n">folder_id</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
                    <span class="k">continue</span>
                <span class="n">folder_id</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">folder_id</span><span class="p">)</span>
                <span class="n">folder_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">folder_id</span><span class="p">][</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
                <span class="n">ismagic</span> <span class="o">=</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">folder_id</span><span class="p">][</span><span class="s2">&quot;isMagic&quot;</span><span class="p">])</span>
                <span class="k">if</span> <span class="n">folder_name</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span> <span class="ow">or</span> <span class="n">ismagic</span><span class="p">:</span>
                    <span class="c1"># skip magic folders like &quot;TopLevelAlbums&quot;</span>
                    <span class="c1"># if someone has a folder with no name, it will be skipped</span>
                    <span class="k">continue</span>
                <span class="n">folder_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">folder_name</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">model_id</span><span class="p">][</span><span class="s2">&quot;folderlist&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">folder_list</span>

        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_albums</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load albums from iPhoto library&quot;&quot;&quot;</span>
        <span class="n">library_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">)</span>

        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKAlbumVersion.modelId,</span>
<span class="s2">            RKAlbumVersion.versionId, -- --&gt;Library::RKVersion::modelId</span>
<span class="s2">            RKAlbumVersion.albumId,</span>
<span class="s2">            RKAlbum.name,</span>
<span class="s2">            RKAlbum.uuid as album_uuid,</span>
<span class="s2">            RKFolder.modelId AS folder_id,</span>
<span class="s2">            RKFolder.uuid AS folder_uuid</span>
<span class="s2">            FROM RKAlbumVersion</span>
<span class="s2">            LEFT JOIN RKAlbum ON RKAlbumVersion.albumId = RKAlbum.modelId</span>
<span class="s2">            LEFT JOIN RKFolder ON RKFolder.uuid = RKAlbum.folderUuid</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">library_db</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading albums from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="n">row</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>
            <span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
            <span class="n">version_id</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;versionId&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">version_id</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_albums</span><span class="p">:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_albums</span><span class="p">[</span><span class="n">version_id</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_albums</span><span class="p">[</span><span class="n">version_id</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">row</span><span class="p">)</span>

        <span class="c1"># get album hierarchy</span>
        <span class="k">for</span> <span class="n">albums</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_albums</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">albums</span><span class="p">:</span>
                <span class="n">album</span><span class="p">[</span><span class="s2">&quot;path&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
                    <span class="o">*</span><span class="bp">self</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">album</span><span class="p">[</span><span class="s2">&quot;folder_id&quot;</span><span class="p">]][</span><span class="s2">&quot;folderlist&quot;</span><span class="p">],</span>
                    <span class="n">album</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">],</span>
                <span class="p">]</span>

        <span class="c1"># add album data to library data</span>
        <span class="k">for</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">library</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;albums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_albums</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">library</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">],</span> <span class="p">[])</span>

        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_keywords</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load keywords from the database&quot;&quot;&quot;</span>

        <span class="n">db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">)</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKVersion.uuid AS uuid,</span>
<span class="s2">            RKKeyword.modelId AS modelId,</span>
<span class="s2">            RKKeyword.name AS name</span>
<span class="s2">            FROM RKKeywordForVersion</span>
<span class="s2">            INNER JOIN RKversion ON RKKeywordForVersion.versionId=RKVersion.modelId</span>
<span class="s2">            INNER JOIN RKKeyword ON RKKeywordForVersion.keywordId=RKKeyword.modelId</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">db</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading keywords from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">:</span>
                <span class="c1"># logger.warning(f&quot;Missing uuid {uuid} in _db_library&quot;)</span>
                <span class="k">continue</span>
            <span class="k">if</span> <span class="s2">&quot;keywords&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;keywords&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;keywords&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">normalize_unicode</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]))</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_image_proxies</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load image proxiesfrom the database&quot;&quot;&quot;</span>

        <span class="n">db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/ImageProxies.apdb&quot;</span><span class="p">)</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">db</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ImageProxies.apdb not found at </span><span class="si">{</span><span class="n">db</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="k">return</span>

        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            modelId as modelId,</span>
<span class="s2">            versionUuid as uuid,</span>
<span class="s2">            fullSizePreviewPath as preview_path</span>
<span class="s2">            FROM RKImageProxyState</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">db</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading preview images from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="n">uuid</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">:</span>
                <span class="c1"># logger.warning(f&quot;Missing uuid {uuid} in _db_library&quot;)</span>
                <span class="k">continue</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;preview_path&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;preview_path&quot;</span><span class="p">]</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_load_volumes</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Load volume data for referenced files&quot;&quot;&quot;</span>
        <span class="n">library_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">)</span>

        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            RKVolume.uuid as uuid,</span>
<span class="s2">            RKVolume.name as name</span>
<span class="s2">            FROM RKVolume</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">library_db</span><span class="p">)</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">verbose</span><span class="p">(</span><span class="s2">&quot;Loading volumes from iPhoto library&quot;</span><span class="p">)</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">:</span>
            <span class="c1"># TODO: does unicode normalization make sense here?</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db_volumes</span><span class="p">[</span><span class="n">row</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">row</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_build_photo_paths</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Build photo paths for each photo in the library&quot;&quot;&quot;</span>

        <span class="c1"># original path</span>
        <span class="k">for</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;is_reference&quot;</span><span class="p">]:</span>
                <span class="n">volume_uuid</span> <span class="o">=</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;volume_uuid&quot;</span><span class="p">]</span>
                <span class="n">volume_name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_volumes</span><span class="p">[</span><span class="n">volume_uuid</span><span class="p">]</span>
                <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;photo_path&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">&quot;/Volumes&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span>
                    <span class="n">volume_name</span><span class="p">,</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;imagepath&quot;</span><span class="p">]</span>
                <span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;photo_path&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span>
                    <span class="s2">&quot;Masters&quot;</span><span class="p">,</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;imagepath&quot;</span><span class="p">]</span>
                <span class="p">)</span>

            <span class="c1"># derivative paths</span>
            <span class="n">image_path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">photo</span><span class="p">[</span><span class="s2">&quot;imagepath&quot;</span><span class="p">])</span>
            <span class="n">path_previews</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span>
                <span class="s2">&quot;Thumbnails&quot;</span><span class="p">,</span> <span class="n">image_path</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">]</span>
            <span class="p">)</span>
            <span class="n">derivatives</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path_previews</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s2">&quot;*&quot;</span><span class="p">))</span>
            <span class="c1"># sort by size, largest first</span>
            <span class="n">derivatives</span><span class="o">.</span><span class="n">sort</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">stat</span><span class="p">()</span><span class="o">.</span><span class="n">st_size</span><span class="p">,</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
            <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;path_derivatives&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">derivatives</span><span class="p">]</span>

            <span class="c1"># edited path</span>
            <span class="k">if</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;hasadjustments&quot;</span><span class="p">]:</span>
                <span class="k">if</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;preview_path&quot;</span><span class="p">]:</span>
                    <span class="c1"># preview path should be read from ImageProxies.apdb</span>
                    <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;path_edited&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span>
                        <span class="s2">&quot;Previews&quot;</span><span class="p">,</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;preview_path&quot;</span><span class="p">]</span>
                    <span class="p">)</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="c1"># fallback to heuristic to find edited image</span>
                    <span class="n">image_path</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">photo</span><span class="p">[</span><span class="s2">&quot;imagepath&quot;</span><span class="p">])</span>
                    <span class="n">path_edited</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span>
                        <span class="s2">&quot;Previews&quot;</span><span class="p">,</span> <span class="n">image_path</span><span class="o">.</span><span class="n">parent</span><span class="p">,</span> <span class="n">uuid</span>
                    <span class="p">)</span>
                    <span class="n">edited_files</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">path_edited</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s2">&quot;*&quot;</span><span class="p">))</span>
                    <span class="c1"># edited image named with Photo&#39;s title not imagepath.stem</span>
                    <span class="k">if</span> <span class="n">edited_files</span> <span class="o">:=</span> <span class="p">[</span>
                        <span class="n">x</span>
                        <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">edited_files</span>
                        <span class="k">if</span> <span class="n">normalize_unicode</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">stem</span><span class="p">)</span> <span class="o">==</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
                    <span class="p">]:</span>
                        <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;path_edited&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">edited_files</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
                    <span class="k">else</span><span class="p">:</span>
                        <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;path_edited&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;path_edited&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>

<div class="viewcode-block" id="iPhotoDB.db_version">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoDB.db_version">[docs]</a>
    <span class="nd">@cached_property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">db_version</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return the database version as stored in Library.apdb RKAdminData table&quot;&quot;&quot;</span>
        <span class="n">library_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">)</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            propertyValue</span>
<span class="s2">            FROM RKAdminData</span>
<span class="s2">            WHERE propertyName IN (&#39;versionMajor&#39;, &#39;versionMinor&#39;);</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">library_db</span><span class="p">)</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">return</span> <span class="s2">&quot;.&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">row</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">results</span><span class="p">)</span></div>


<div class="viewcode-block" id="iPhotoDB.photos_version">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoDB.photos_version">[docs]</a>
    <span class="nd">@cached_property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">photos_version</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns version of the library as a string&quot;&quot;&quot;</span>
        <span class="n">library_db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">library_path</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database/apdb/Library.apdb&quot;</span><span class="p">)</span>
        <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
<span class="s2">            SELECT</span>
<span class="s2">            propertyValue</span>
<span class="s2">            FROM RKAdminData</span>
<span class="s2">            WHERE propertyName IN (&#39;applicationIdentifier&#39;);</span>
<span class="s2">        &quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Executing query: </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>

        <span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">library_db</span><span class="p">)</span>
        <span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
        <span class="n">results</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2"> - </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">db_version</span><span class="si">}</span><span class="s2">&quot;</span></div>


<div class="viewcode-block" id="iPhotoDB.get_db_connection">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoDB.get_db_connection">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_db_connection</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">sqlite3</span><span class="o">.</span><span class="n">Connection</span><span class="p">,</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Cursor</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get connection to the working copy of the Photos database</span>

<span class="sd">        Returns:</span>
<span class="sd">            tuple of (connection, cursor) to sqlite3 database</span>

<span class="sd">        Raises:</span>
<span class="sd">            NotImplementedError on iPhoto</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span><span class="s2">&quot;get_db_connection not implemented for iPhoto&quot;</span><span class="p">)</span></div>


    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">keywords_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return keywords as dict of list of keywords keyed by count of photos&quot;&quot;&quot;</span>
        <span class="n">keywords</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">if</span> <span class="s2">&quot;keywords&quot;</span> <span class="ow">in</span> <span class="n">photo</span><span class="p">:</span>
                <span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;keywords&quot;</span><span class="p">]:</span>
                    <span class="k">if</span> <span class="n">keyword</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">keywords</span><span class="p">:</span>
                        <span class="n">keywords</span><span class="p">[</span><span class="n">keyword</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
                    <span class="n">keywords</span><span class="p">[</span><span class="n">keyword</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="n">keywords</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">persons_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return persons as dict of list of persons keyed count of photos&quot;&quot;&quot;</span>
        <span class="n">persons</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;hasadjustments&quot;</span><span class="p">]:</span>
                <span class="n">face_list</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;edited_faces&quot;</span><span class="p">,</span> <span class="p">[])</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">face_list</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;faces&quot;</span><span class="p">,</span> <span class="p">[])</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">face_list</span><span class="p">:</span>
                <span class="n">face_name</span> <span class="o">=</span> <span class="n">face</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">face_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">persons</span><span class="p">:</span>
                    <span class="n">persons</span><span class="p">[</span><span class="n">face_name</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="n">persons</span><span class="p">[</span><span class="n">face_name</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="n">persons</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">albums_as_dict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return albums as dict of list of albums keyed by count of photos&quot;&quot;&quot;</span>
        <span class="n">albums</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;albums&quot;</span><span class="p">]:</span>
                <span class="n">album_name</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">album_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">albums</span><span class="p">:</span>
                    <span class="n">albums</span><span class="p">[</span><span class="n">album_name</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="n">albums</span><span class="p">[</span><span class="n">album_name</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="n">albums</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">album_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoAlbumInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of iPhotoAlbumInfo objects for each album in the library&quot;&quot;&quot;</span>
        <span class="n">album_info</span> <span class="o">=</span> <span class="p">{}</span>
        <span class="k">for</span> <span class="n">albums</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_albums</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">albums</span><span class="p">:</span>
                <span class="k">if</span> <span class="n">album</span><span class="p">[</span><span class="s2">&quot;album_uuid&quot;</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">album_info</span><span class="p">:</span>
                    <span class="n">album_info</span><span class="p">[</span><span class="n">album</span><span class="p">[</span><span class="s2">&quot;album_uuid&quot;</span><span class="p">]]</span> <span class="o">=</span> <span class="n">iPhotoAlbumInfo</span><span class="p">(</span><span class="n">album</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">album_info</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">albums</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of album names&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">albums_as_dict</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>

<div class="viewcode-block" id="iPhotoDB.photos">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoDB.photos">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">photos</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span>
        <span class="n">keywords</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">uuid</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">persons</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">albums</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">images</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
        <span class="n">movies</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
        <span class="n">from_date</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">to_date</span><span class="p">:</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">intrash</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoPhotoInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return a list of iPhotoPhotoInfo objects</span>
<span class="sd">        If called with no args, returns the entire database of photos</span>
<span class="sd">        If called with args, returns photos matching the args (e.g. keywords, persons, etc.)</span>
<span class="sd">        If more than one arg, returns photos matching all the criteria (e.g. keywords AND persons)</span>
<span class="sd">        If more than one keyword, uuid, persons, albums is passed, they are treated as &quot;OR&quot; criteria</span>
<span class="sd">        e.g. keywords=[&quot;wedding&quot;,&quot;vacation&quot;] returns photos matching either keyword</span>
<span class="sd">        from_date and to_date may be either naive or timezone-aware datetime.datetime objects.</span>
<span class="sd">        If naive, timezone will be assumed to be local timezone.</span>

<span class="sd">        Args:</span>
<span class="sd">            keywords: list of keywords to search for</span>
<span class="sd">            uuid: list of UUIDs to search for</span>
<span class="sd">            persons: list of persons to search for</span>
<span class="sd">            albums: list of album names to search for</span>
<span class="sd">            images: if True, returns image files, if False, does not return images; default is True</span>
<span class="sd">            movies: if True, returns movie files, if False, does not return movies; default is True</span>
<span class="sd">            from_date: return photos with creation date &gt;= from_date (datetime.datetime object, default None)</span>
<span class="sd">            to_date: return photos with creation date &lt; to_date (datetime.datetime object, default None)</span>
<span class="sd">            intrash: if True, returns only images in &quot;Recently deleted items&quot; folder,</span>
<span class="sd">                     if False returns only photos that aren&#39;t deleted; default is False</span>

<span class="sd">        Returns:</span>
<span class="sd">            list of iPhotoPhotoInfo objects</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">iPhotoPhotoInfo</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span> <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">uuid</span><span class="p">:</span>
            <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">photo</span> <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">uuid</span> <span class="ow">in</span> <span class="n">uuid</span><span class="p">]</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">images</span><span class="p">:</span>
            <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">photo</span> <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">photo</span><span class="o">.</span><span class="n">isphoto</span><span class="p">]</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">movies</span><span class="p">:</span>
            <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">photo</span> <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">photo</span><span class="o">.</span><span class="n">ismovie</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">keywords</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">keywords</span><span class="p">:</span>
                <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span>
                    <span class="n">photo</span>
                    <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span>
                    <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">keywords</span> <span class="ow">and</span> <span class="n">keyword</span> <span class="ow">in</span> <span class="n">photo</span><span class="o">.</span><span class="n">keywords</span>
                <span class="p">]</span>
        <span class="k">if</span> <span class="n">persons</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">persons</span><span class="p">:</span>
                <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span>
                    <span class="n">photo</span>
                    <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span>
                    <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">persons</span> <span class="ow">and</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">photo</span><span class="o">.</span><span class="n">persons</span>
                <span class="p">]</span>
        <span class="k">if</span> <span class="n">albums</span><span class="p">:</span>
            <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">albums</span><span class="p">:</span>
                <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span>
                    <span class="n">photo</span> <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">albums</span> <span class="ow">and</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">photo</span><span class="o">.</span><span class="n">albums</span>
                <span class="p">]</span>
        <span class="k">if</span> <span class="n">from_date</span><span class="p">:</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">datetime_has_tz</span><span class="p">(</span><span class="n">from_date</span><span class="p">):</span>
                <span class="n">from_date</span> <span class="o">=</span> <span class="n">datetime_naive_to_local</span><span class="p">(</span><span class="n">from_date</span><span class="p">)</span>
            <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">photo</span> <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">date</span> <span class="o">&gt;=</span> <span class="n">from_date</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">to_date</span><span class="p">:</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">datetime_has_tz</span><span class="p">(</span><span class="n">to_date</span><span class="p">):</span>
                <span class="n">to_date</span> <span class="o">=</span> <span class="n">datetime_naive_to_local</span><span class="p">(</span><span class="n">to_date</span><span class="p">)</span>
            <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">photo</span> <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">date</span> <span class="o">&lt;</span> <span class="n">to_date</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">intrash</span><span class="p">:</span>
            <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">photo</span> <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">intrash</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">photo</span> <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="n">photos</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">photo</span><span class="o">.</span><span class="n">intrash</span><span class="p">]</span>
        <span class="k">return</span> <span class="n">photos</span></div>


<div class="viewcode-block" id="iPhotoDB.get_photo">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoDB.get_photo">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">get_photo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoPhotoInfo</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return photo by uuid&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">uuid</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Photo with uuid </span><span class="si">{</span><span class="n">uuid</span><span class="si">}</span><span class="s2"> not found&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">iPhotoPhotoInfo</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span></div>


<div class="viewcode-block" id="iPhotoDB.query">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoDB.query">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">options</span><span class="p">:</span> <span class="n">QueryOptions</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoPhotoInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Run a query against PhotosDB to extract the photos based on user supplied options</span>

<span class="sd">        Args:</span>
<span class="sd">            options: a QueryOptions instance</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">photo_query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span></div>


    <span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;osxphotos.</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">(dbfile=&#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">db_path</span><span class="si">}</span><span class="s2">&#39;)&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return number of photos in the library&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">photos</span><span class="p">())</span></div>



<div class="viewcode-block" id="iPhotoPhotoInfo">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoPhotoInfo</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;PhotoInfo implementation for iPhoto&quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">uuid</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">db</span><span class="p">:</span> <span class="n">iPhotoDB</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span> <span class="o">=</span> <span class="n">uuid</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_info</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;id&quot;</span><span class="p">]</span>  <span class="c1"># modelID / versionId</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_attributes</span> <span class="o">=</span> <span class="n">get_user_attributes</span><span class="p">(</span><span class="n">PhotoInfo</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_verbose</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">_verbose</span>  <span class="c1"># compatibility with PhotoInfo</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;UUID of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">filename</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Filename of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;filename&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">original_filename</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Original filename of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;filename&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">isphoto</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if asset is a photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;mediatype&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;IMGT&quot;</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">ismovie</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if asset is a movie&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;mediatype&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;VIDT&quot;</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">israw</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if asset is a raw image&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;truly_raw&quot;</span><span class="p">])</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">raw_original</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if asset original is a raw image&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;truly_raw&quot;</span><span class="p">])</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uti</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;UTI of current version of photo (edited if hasadjustments, otherwise original)&quot;&quot;&quot;</span>
        <span class="c1"># this isn&#39;t stored in the database so we have to determine from filename</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">get_uti_for_path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">get_uti_for_path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uti_original</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;UTI of original version of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">get_uti_for_path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uti_edited</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;UTI of edited version of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span>
            <span class="n">get_uti_for_path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span><span class="p">)</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span>
            <span class="k">else</span> <span class="kc">None</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uti_raw</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;UTI of raw version of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">get_uti_for_path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">israw</span> <span class="k">else</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">ismissing</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if asset is missing&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;ismissing&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">isreference</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return True if asset is a referenced file&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;is_reference&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">date</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Date photo was taken&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">photos_datetime</span><span class="p">(</span>
            <span class="n">timestamp</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;date_taken&quot;</span><span class="p">],</span>
            <span class="n">tzname</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;timezone&quot;</span><span class="p">],</span>
            <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">date_original</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Date photo was taken&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">date</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">date_modified</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Date modified in library&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">photos_datetime</span><span class="p">(</span>
            <span class="n">timestamp</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;date_modified&quot;</span><span class="p">],</span>
            <span class="n">tzname</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;timezone&quot;</span><span class="p">],</span>
            <span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">date_added</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Date added to library&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">photos_datetime</span><span class="p">(</span>
            <span class="n">timestamp</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;date_imported&quot;</span><span class="p">],</span>
            <span class="n">tzname</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;timezone&quot;</span><span class="p">],</span>
            <span class="n">default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">tzoffset</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;TZ Offset from GMT in seconds&quot;&quot;&quot;</span>
        <span class="n">tzname</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;timezone&quot;</span><span class="p">]</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">utcoffset</span><span class="p">()</span><span class="o">.</span><span class="n">total_seconds</span><span class="p">())</span>
        <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to get timezone info for </span><span class="si">{</span><span class="n">tzname</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="mi">0</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">tzname</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Timezone name for the asset creation date&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;timezone&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">path</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Path to original photo asset in library&quot;&quot;&quot;</span>
        <span class="n">path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;photo_path&quot;</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">path_exists</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
            <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Photo path </span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2"> does not exist&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">path_edited</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Path to edited asset in library&quot;&quot;&quot;</span>
        <span class="n">path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;path_edited&quot;</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">path_exists</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
            <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Edited photo path </span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2"> does not exist&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">path_derivatives</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Path to derivatives in library&quot;&quot;&quot;</span>
        <span class="c1"># don&#39;t need to check for existence since we just globbed the directory</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;path_derivatives&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">description</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Description of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">title</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Title of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">favorite</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns True if photo is favorite; iPhoto doesn&#39;t have favorite so always returns False&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="kc">False</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">flagged</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns True if photo is flagged&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;flagged&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">))</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">rating</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Rating of photo as int from 0 to 5&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;rating&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">hidden</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;True if photo is hidden&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;hidden&quot;</span><span class="p">])</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">visible</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;True if photo is visible in Photos; always returns False for iPhoto&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;visible not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">False</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">intrash</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;True if photo is in the Photos trash&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;in_trash&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">persons</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;List of persons in photo&quot;&quot;&quot;</span>
        <span class="n">faces</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_faces</span><span class="p">()</span>
        <span class="n">persons</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">faces</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">person</span> <span class="o">:=</span> <span class="n">face</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]:</span>
                <span class="n">persons</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">person</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">persons</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_UNKNOWN_PERSON</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">persons</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">person_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoPersonInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;List of iPhotoPersonInfo objects for photo&quot;&quot;&quot;</span>
        <span class="n">faces</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_faces</span><span class="p">()</span>
        <span class="k">return</span> <span class="nb">sorted</span><span class="p">(</span>
            <span class="p">[</span><span class="n">iPhotoPersonInfo</span><span class="p">(</span><span class="n">face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span> <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">faces</span><span class="p">],</span>
            <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">name</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">face_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoFaceInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;List of iPhotoFaceInfo objects for photo&quot;&quot;&quot;</span>
        <span class="n">faces</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_get_faces</span><span class="p">()</span>
        <span class="k">return</span> <span class="nb">sorted</span><span class="p">(</span>
            <span class="p">[</span><span class="n">iPhotoFaceInfo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span> <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">faces</span><span class="p">],</span>
            <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">name</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">keywords</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Keywords for photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">sorted</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;keywords&quot;</span><span class="p">,</span> <span class="p">[]))</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">hasadjustments</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;True if photo has adjustments&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;hasadjustments&quot;</span><span class="p">])</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">width</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Width of photo in pixels&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;processed_width&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">height</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Height of photo in pixels&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;processed_height&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">original_width</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Original width of photo in pixels&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;master_width&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">original_height</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Original height of photo in pixels&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;master_height&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">latitude</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Latitude of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;latitude&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">longitude</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Longitude of photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;longitude&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">location</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]</span> <span class="o">|</span> <span class="nb">tuple</span><span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Location of photo as (latitude, longitude)&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">latitude</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">longitude</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">original_filesize</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Size of original file in bytes&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">][</span><span class="s2">&quot;original_filesize&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">albums</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;List of albums photo is contained in&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">sorted</span><span class="p">(</span>
            <span class="p">[</span>
                <span class="n">album</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
                <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;albums&quot;</span><span class="p">,</span> <span class="p">[])</span>
            <span class="p">],</span>
            <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">album_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoAlbumInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot; &quot;Return list of iPhotoAlbumInfo objects for photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">sorted</span><span class="p">(</span>
            <span class="p">[</span>
                <span class="n">iPhotoAlbumInfo</span><span class="p">(</span><span class="n">album</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;albums&quot;</span><span class="p">,</span> <span class="p">[])</span>
            <span class="p">],</span>
            <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">.</span><span class="n">title</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">event_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoEventInfo</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return iPhotoEventInfo object for photo or None if photo is not in an event&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">event</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;roll&quot;</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">event_data</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_folders</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
                <span class="k">return</span> <span class="n">iPhotoEventInfo</span><span class="p">(</span><span class="n">event_data</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">moment_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoMomentInfo</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return iPhotoMomentInfo object for photo or None if photo is not in a moment; for iPhoto returns event as moment&quot;&quot;&quot;</span>
        <span class="c1"># iPhoto doesn&#39;t actually have moment so use event</span>
        <span class="k">if</span> <span class="n">event</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;roll&quot;</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">event_data</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_folders</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">event</span><span class="p">):</span>
                <span class="k">return</span> <span class="n">iPhotoMomentInfo</span><span class="p">(</span><span class="n">event_data</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span>

<div class="viewcode-block" id="iPhotoPhotoInfo.fingerprint">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo.fingerprint">[docs]</a>
    <span class="nd">@cached_property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">fingerprint</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns fingerprint of original photo as a string; returns None if not available. On linux, returns None.&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">is_macos</span><span class="p">:</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s2">&quot;fingerprint only supported on macOS&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="kc">None</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">:</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Missing path, cannot compute fingerprint for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="kc">None</span>

        <span class="k">return</span> <span class="n">fingerprint</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">)</span></div>


<div class="viewcode-block" id="iPhotoPhotoInfo.exif_info">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo.exif_info">[docs]</a>
    <span class="nd">@cached_property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">exif_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoExifInfo</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return iPhotoExifInfo object for photo&quot;&quot;&quot;</span>

        <span class="n">exif_info</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_id</span><span class="p">,</span> <span class="p">{})</span>
        <span class="k">return</span> <span class="n">iPhotoExifInfo</span><span class="p">(</span>
            <span class="n">flash_fired</span><span class="o">=</span><span class="nb">bool</span><span class="p">(</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Flash&quot;</span><span class="p">,</span> <span class="kc">False</span><span class="p">)),</span>
            <span class="n">iso</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;ISOSpeedRating&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
            <span class="n">metering_mode</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;MeteringMode&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
            <span class="n">sample_rate</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
            <span class="n">track_format</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span>
            <span class="n">white_balance</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;WhiteBalance&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span>
            <span class="n">aperture</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;ApertureValue&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">bit_rate</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;DataRate&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">duration</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;MovieDuration&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">exposure_bias</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;ExposureBiasValue&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">focal_length</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;FocalLength&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">fps</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;FPS&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">latitude</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Latitude&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">longitude</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Longitude&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">shutter_speed</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;ShutterSpeed&quot;</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">),</span>
            <span class="n">camera_make</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Make&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">),</span>
            <span class="n">camera_model</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Model&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">),</span>
            <span class="n">codec</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span>
            <span class="n">lens_model</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;LensModel&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">),</span>
            <span class="n">software</span><span class="o">=</span><span class="n">exif_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Software&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">),</span>
            <span class="nb">dict</span><span class="o">=</span><span class="n">exif_info</span><span class="p">,</span>
        <span class="p">)</span></div>


    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">burst_albums</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;For iPhoto, returns self.albums; this is different behavior than Photos&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">albums</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">burst_album_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoAlbumInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;For iPhoto, returns self.album_info; this is different behavior than Photos&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">album_info</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">burst</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns True if photo is part of a Burst photo set, otherwise False&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;burst_uuid&quot;</span><span class="p">])</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">burst_photos</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">PhotoInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;If photo is a burst photo, returns list of iPhotoPhotoInfo objects</span>
<span class="sd">        that are part of the same burst photo set; otherwise returns empty list.</span>
<span class="sd">        self is not included in the returned list&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">[]</span>

        <span class="n">burst_uuid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;burst_uuid&quot;</span><span class="p">]</span>
        <span class="k">return</span> <span class="p">[</span>
            <span class="n">iPhotoPhotoInfo</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">uuid</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span>
            <span class="k">if</span> <span class="n">uuid</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span>
            <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="n">uuid</span><span class="p">][</span><span class="s2">&quot;burst_uuid&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">burst_uuid</span>
        <span class="p">]</span>

<div class="viewcode-block" id="iPhotoPhotoInfo.hexdigest">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo.hexdigest">[docs]</a>
    <span class="nd">@cached_property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">hexdigest</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns a unique digest of the photo&#39;s properties and metadata;</span>
<span class="sd">        useful for detecting changes in any property/metadata of the photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">hexdigest</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_json_hexdigest</span><span class="p">())</span></div>


    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">score</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ScoreInfo</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">ScoreInfo</span><span class="p">(</span>
            <span class="n">overall</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">curation</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">promotion</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">highlight_visibility</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">behavioral</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">failure</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">harmonious_color</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">immersiveness</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">interaction</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">interesting_subject</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">intrusive_object_presence</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">lively_color</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">low_light</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">noise</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">pleasant_camera_tilt</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">pleasant_composition</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">pleasant_lighting</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">pleasant_pattern</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">pleasant_perspective</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">pleasant_post_processing</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">pleasant_reflection</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">pleasant_symmetry</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">sharply_focused_subject</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">tastefully_blurred</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">well_chosen_subject</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">well_framed_subject</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
            <span class="n">well_timed_shot</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">orientation</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns EXIF orientation of the current photo version as int or 0 if current orientation cannot be determined&quot;&quot;&quot;</span>
        <span class="c1"># iPhoto doesn&#39;t store orientation but does store rotation from which we can get orientation</span>
        <span class="n">rotation</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;rotation&quot;</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">rotation</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
            <span class="k">return</span> <span class="mi">0</span>
        <span class="k">return</span> <span class="n">angle_to_exif_orientation</span><span class="p">(</span><span class="n">rotation</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">media_analysis</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns media analysis results as a dictionary (Photos 5+)&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">dict</span><span class="p">()</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">ai_caption</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns AI generated caption for photo or video (Photos 5+)&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="s2">&quot;&quot;</span>

<div class="viewcode-block" id="iPhotoPhotoInfo.export">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo.export">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">export</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span>
        <span class="n">dest</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
        <span class="n">filename</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">edited</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">raw_photo</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">export_as_hardlink</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">overwrite</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">increment</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">,</span>
        <span class="n">sidecar_json</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">sidecar_exiftool</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">sidecar_xmp</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">exiftool</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">use_albums_as_keywords</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">use_persons_as_keywords</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
        <span class="n">keyword_template</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">description_template</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="n">render_options</span><span class="p">:</span> <span class="n">RenderOptions</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
        <span class="o">**</span><span class="n">kwargs</span><span class="p">,</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Export a photo</span>

<span class="sd">        Args:</span>
<span class="sd">            dest: must be valid destination path (or exception raised)</span>
<span class="sd">            filename: (optional): name of exported picture; if not provided, will use current filename</span>
<span class="sd">              **NOTE**: if provided, user must ensure file extension (suffix) is correct.</span>
<span class="sd">              For example, if photo is .CR2 file, edited image may be .jpeg.</span>
<span class="sd">              If you provide an extension different than what the actual file is,</span>
<span class="sd">              export will print a warning but will export the photo using the</span>
<span class="sd">              incorrect file extension (unless use_photos_export is true, in which case export will</span>
<span class="sd">              use the extension provided by Photos upon export; in this case, an incorrect extension is</span>
<span class="sd">              silently ignored).</span>
<span class="sd">              e.g. to get the extension of the edited photo,</span>
<span class="sd">              reference iPhotoPhotoInfo.path_edited</span>
<span class="sd">            edited: (boolean, default=False); if True will export the edited version of the photo, otherwise exports the original version</span>
<span class="sd">              (or raise exception if no edited version)</span>
<span class="sd">            raw_photo: (boolean, default=False); if True, will also export the associated RAW photo</span>
<span class="sd">            export_as_hardlink: (boolean, default=False); if True, will hardlink files instead of copying them</span>
<span class="sd">            overwrite: (boolean, default=False); if True will overwrite files if they already exist</span>
<span class="sd">            increment: (boolean, default=True); if True, will increment file name until a non-existant name is found</span>
<span class="sd">              if overwrite=False and increment=False, export will fail if destination file already exists</span>
<span class="sd">            sidecar_json: if set will write a json sidecar with data in format readable by exiftool</span>
<span class="sd">              sidecar filename will be dest/filename.json; includes exiftool tag group names (e.g. &#39;exiftool -G -j&#39;)</span>
<span class="sd">            sidecar_exiftool: if set will write a json sidecar with data in format readable by exiftool</span>
<span class="sd">              sidecar filename will be dest/filename.json; does not include exiftool tag group names (e.g. &#39;exiftool -j&#39;)</span>
<span class="sd">            sidecar_xmp: if set will write an XMP sidecar with IPTC data</span>
<span class="sd">              sidecar filename will be dest/filename.xmp</span>
<span class="sd">            exiftool: (boolean, default = False); if True, will use exiftool to write metadata to export file</span>
<span class="sd">            returns list of full paths to the exported files</span>
<span class="sd">            use_albums_as_keywords: (boolean, default = False); if True, will include album names in keywords</span>
<span class="sd">            when exporting metadata with exiftool or sidecar</span>
<span class="sd">            use_persons_as_keywords: (boolean, default = False); if True, will include person names in keywords</span>
<span class="sd">            when exporting metadata with exiftool or sidecar</span>
<span class="sd">            keyword_template: (list of strings); list of template strings that will be rendered as used as keywords</span>
<span class="sd">            description_template: string; optional template string that will be rendered for use as photo description</span>
<span class="sd">            render_options: an optional osxphotos.phototemplate.RenderOptions instance with options to pass to template renderer</span>

<span class="sd">        Returns: list of paths to photos exported</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">if</span> <span class="n">kwargs</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">NotImplementedError</span><span class="p">(</span>
                <span class="sa">f</span><span class="s2">&quot;Unsupported export options: </span><span class="si">{</span><span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">kwargs</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="si">}</span><span class="s2">&quot;</span>
            <span class="p">)</span>

        <span class="n">exporter</span> <span class="o">=</span> <span class="n">PhotoExporter</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
        <span class="n">sidecar</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">if</span> <span class="n">sidecar_json</span><span class="p">:</span>
            <span class="n">sidecar</span> <span class="o">|=</span> <span class="n">SIDECAR_JSON</span>
        <span class="k">if</span> <span class="n">sidecar_exiftool</span><span class="p">:</span>
            <span class="n">sidecar</span> <span class="o">|=</span> <span class="n">SIDECAR_EXIFTOOL</span>
        <span class="k">if</span> <span class="n">sidecar_xmp</span><span class="p">:</span>
            <span class="n">sidecar</span> <span class="o">|=</span> <span class="n">SIDECAR_XMP</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="n">filename</span><span class="p">:</span>
            <span class="k">if</span> <span class="ow">not</span> <span class="n">edited</span><span class="p">:</span>
                <span class="n">filename</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_filename</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">original_name</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">original_filename</span><span class="p">)</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span><span class="p">:</span>
                    <span class="n">ext</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span><span class="p">)</span><span class="o">.</span><span class="n">suffix</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="n">uti</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti_edited</span> <span class="k">if</span> <span class="n">edited</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti_edited</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti</span>
                    <span class="n">ext</span> <span class="o">=</span> <span class="n">get_preferred_uti_extension</span><span class="p">(</span><span class="n">uti</span><span class="p">)</span>
                    <span class="n">ext</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;.</span><span class="si">{</span><span class="n">ext</span><span class="si">}</span><span class="s2">&quot;</span>
                <span class="n">filename</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">original_name</span><span class="o">.</span><span class="n">stem</span><span class="si">}</span><span class="s2">_edited</span><span class="si">{</span><span class="n">ext</span><span class="si">}</span><span class="s2">&quot;</span>

        <span class="n">options</span> <span class="o">=</span> <span class="n">ExportOptions</span><span class="p">(</span>
            <span class="n">description_template</span><span class="o">=</span><span class="n">description_template</span><span class="p">,</span>
            <span class="n">edited</span><span class="o">=</span><span class="n">edited</span><span class="p">,</span>
            <span class="n">exiftool</span><span class="o">=</span><span class="n">exiftool</span><span class="p">,</span>
            <span class="n">export_as_hardlink</span><span class="o">=</span><span class="n">export_as_hardlink</span><span class="p">,</span>
            <span class="n">increment</span><span class="o">=</span><span class="n">increment</span><span class="p">,</span>
            <span class="n">keyword_template</span><span class="o">=</span><span class="n">keyword_template</span><span class="p">,</span>
            <span class="n">overwrite</span><span class="o">=</span><span class="n">overwrite</span><span class="p">,</span>
            <span class="n">raw_photo</span><span class="o">=</span><span class="n">raw_photo</span><span class="p">,</span>
            <span class="n">render_options</span><span class="o">=</span><span class="n">render_options</span><span class="p">,</span>
            <span class="n">sidecar</span><span class="o">=</span><span class="n">sidecar</span><span class="p">,</span>
            <span class="n">use_albums_as_keywords</span><span class="o">=</span><span class="n">use_albums_as_keywords</span><span class="p">,</span>
            <span class="n">use_persons_as_keywords</span><span class="o">=</span><span class="n">use_persons_as_keywords</span><span class="p">,</span>
        <span class="p">)</span>

        <span class="n">results</span> <span class="o">=</span> <span class="n">exporter</span><span class="o">.</span><span class="n">export</span><span class="p">(</span><span class="n">dest</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="n">filename</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="n">options</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">results</span><span class="o">.</span><span class="n">exported</span></div>


<div class="viewcode-block" id="iPhotoPhotoInfo.render_template">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo.render_template">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">render_template</span><span class="p">(</span>
        <span class="bp">self</span><span class="p">,</span> <span class="n">template_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">options</span><span class="p">:</span> <span class="n">RenderOptions</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
    <span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Renders a template string for iPhotoPhotoInfo instance using PhotoTemplate</span>

<span class="sd">        Args:</span>
<span class="sd">            template_str: a template string with fields to render</span>
<span class="sd">            options: a RenderOptions instance</span>

<span class="sd">        Returns:</span>
<span class="sd">            ([rendered_strings], [unmatched]): tuple of list of rendered strings and list of unmatched template values</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">options</span> <span class="o">=</span> <span class="n">options</span> <span class="ow">or</span> <span class="n">RenderOptions</span><span class="p">()</span>
        <span class="n">template</span> <span class="o">=</span> <span class="n">PhotoTemplate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">exiftool_path</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_exiftool_path</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="n">template_str</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span></div>


<div class="viewcode-block" id="iPhotoPhotoInfo.exiftool">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo.exiftool">[docs]</a>
    <span class="nd">@cached_property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">exiftool</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ExifToolCaching</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns a ExifToolCaching (read-only instance of ExifTool) object for the photo.</span>
<span class="sd">        Requires that exiftool (https://exiftool.org/) be installed</span>
<span class="sd">        If exiftool not installed, logs warning and returns None</span>
<span class="sd">        If photo path is missing, returns None</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">exiftool_path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_exiftool_path</span> <span class="ow">or</span> <span class="n">get_exiftool_path</span><span class="p">()</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">path</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">)</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
                <span class="n">exiftool</span> <span class="o">=</span> <span class="n">ExifToolCaching</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">,</span> <span class="n">exiftool</span><span class="o">=</span><span class="n">exiftool_path</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">exiftool</span> <span class="o">=</span> <span class="kc">None</span>
        <span class="k">except</span> <span class="ne">FileNotFoundError</span><span class="p">:</span>
            <span class="c1"># get_exiftool_path raises FileNotFoundError if exiftool not found</span>
            <span class="n">exiftool</span> <span class="o">=</span> <span class="kc">None</span>
            <span class="n">logging</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
                <span class="s2">&quot;exiftool not in path; download and install from https://exiftool.org/&quot;</span>
            <span class="p">)</span>
        <span class="k">return</span> <span class="n">exiftool</span></div>


<div class="viewcode-block" id="iPhotoPhotoInfo.asdict">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo.asdict">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shallow</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return dict representation of iPhotoPhotoInfo object.</span>

<span class="sd">        Args:</span>
<span class="sd">            shallow: if True, return shallow representation (does not contain folder_info, person_info, etc.)</span>

<span class="sd">        Returns:</span>
<span class="sd">            dict representation of iPhotoPhotoInfo object</span>

<span class="sd">        Note:</span>
<span class="sd">            The shallow representation is used internally by export as it contains only the subset of data needed for export.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="n">comments</span> <span class="o">=</span> <span class="p">[</span><span class="n">comment</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">for</span> <span class="n">comment</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">comments</span><span class="p">]</span>
        <span class="n">exif_info</span> <span class="o">=</span> <span class="n">dataclasses</span><span class="o">.</span><span class="n">asdict</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">exif_info</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">exif_info</span> <span class="k">else</span> <span class="p">{}</span>
        <span class="n">face_info</span> <span class="o">=</span> <span class="p">[</span><span class="n">face</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">face_info</span><span class="p">]</span>
        <span class="n">folders</span> <span class="o">=</span> <span class="p">{</span><span class="n">album</span><span class="o">.</span><span class="n">title</span><span class="p">:</span> <span class="n">album</span><span class="o">.</span><span class="n">folder_names</span> <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">album_info</span><span class="p">}</span>
        <span class="n">likes</span> <span class="o">=</span> <span class="p">[</span><span class="n">like</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">for</span> <span class="n">like</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">likes</span><span class="p">]</span>
        <span class="n">place</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">place</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">place</span> <span class="k">else</span> <span class="p">{}</span>
        <span class="n">score</span> <span class="o">=</span> <span class="n">dataclasses</span><span class="o">.</span><span class="n">asdict</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">score</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">score</span> <span class="k">else</span> <span class="p">{}</span>

        <span class="c1"># do not add any new properties to data_dict as this is used by export to determine</span>
        <span class="c1"># if a photo needs to be re-exported and adding new properties may cause all photos</span>
        <span class="c1"># to be re-exported</span>
        <span class="c1"># see below &#39;if not shallow:&#39;</span>
        <span class="n">dict_data</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s2">&quot;albums&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">albums</span><span class="p">,</span>
            <span class="s2">&quot;burst&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst</span><span class="p">,</span>
            <span class="s2">&quot;cloud_guid&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">cloud_guid</span><span class="p">,</span>
            <span class="s2">&quot;cloud_owner_hashed_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">cloud_owner_hashed_id</span><span class="p">,</span>
            <span class="s2">&quot;comments&quot;</span><span class="p">:</span> <span class="n">comments</span><span class="p">,</span>
            <span class="s2">&quot;date_added&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">date_added</span><span class="p">,</span>
            <span class="s2">&quot;date_modified&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">date_modified</span><span class="p">,</span>
            <span class="s2">&quot;date_trashed&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">date_trashed</span><span class="p">,</span>
            <span class="s2">&quot;date&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">date</span><span class="p">,</span>
            <span class="s2">&quot;description&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">description</span><span class="p">,</span>
            <span class="s2">&quot;exif_info&quot;</span><span class="p">:</span> <span class="n">exif_info</span><span class="p">,</span>
            <span class="s2">&quot;external_edit&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">external_edit</span><span class="p">,</span>
            <span class="s2">&quot;face_info&quot;</span><span class="p">:</span> <span class="n">face_info</span><span class="p">,</span>
            <span class="s2">&quot;favorite&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">favorite</span><span class="p">,</span>
            <span class="s2">&quot;filename&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">,</span>
            <span class="s2">&quot;fingerprint&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fingerprint</span><span class="p">,</span>
            <span class="s2">&quot;folders&quot;</span><span class="p">:</span> <span class="n">folders</span><span class="p">,</span>
            <span class="s2">&quot;has_raw&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">has_raw</span><span class="p">,</span>
            <span class="s2">&quot;hasadjustments&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">,</span>
            <span class="s2">&quot;hdr&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">hdr</span><span class="p">,</span>
            <span class="s2">&quot;height&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">height</span><span class="p">,</span>
            <span class="s2">&quot;hidden&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">hidden</span><span class="p">,</span>
            <span class="s2">&quot;incloud&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">incloud</span><span class="p">,</span>
            <span class="s2">&quot;intrash&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">intrash</span><span class="p">,</span>
            <span class="s2">&quot;iscloudasset&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">iscloudasset</span><span class="p">,</span>
            <span class="s2">&quot;ismissing&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">ismissing</span><span class="p">,</span>
            <span class="s2">&quot;ismovie&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">ismovie</span><span class="p">,</span>
            <span class="s2">&quot;isphoto&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">isphoto</span><span class="p">,</span>
            <span class="s2">&quot;israw&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">israw</span><span class="p">,</span>
            <span class="s2">&quot;isreference&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">isreference</span><span class="p">,</span>
            <span class="s2">&quot;keywords&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span><span class="p">,</span>
            <span class="s2">&quot;labels&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">labels</span><span class="p">,</span>
            <span class="s2">&quot;latitude&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_latitude</span><span class="p">,</span>
            <span class="s2">&quot;library&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_library_path</span><span class="p">,</span>
            <span class="s2">&quot;likes&quot;</span><span class="p">:</span> <span class="n">likes</span><span class="p">,</span>
            <span class="s2">&quot;live_photo&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">live_photo</span><span class="p">,</span>
            <span class="s2">&quot;location&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="p">,</span>
            <span class="s2">&quot;longitude&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_longitude</span><span class="p">,</span>
            <span class="s2">&quot;orientation&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">orientation</span><span class="p">,</span>
            <span class="s2">&quot;original_filename&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_filename</span><span class="p">,</span>
            <span class="s2">&quot;original_filesize&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_filesize</span><span class="p">,</span>
            <span class="s2">&quot;original_height&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_height</span><span class="p">,</span>
            <span class="s2">&quot;original_orientation&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_orientation</span><span class="p">,</span>
            <span class="s2">&quot;original_width&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_width</span><span class="p">,</span>
            <span class="s2">&quot;owner&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">owner</span><span class="p">,</span>
            <span class="s2">&quot;panorama&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">panorama</span><span class="p">,</span>
            <span class="s2">&quot;path_edited_live_photo&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_edited_live_photo</span><span class="p">,</span>
            <span class="s2">&quot;path_edited&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span><span class="p">,</span>
            <span class="s2">&quot;path_live_photo&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_live_photo</span><span class="p">,</span>
            <span class="s2">&quot;path_raw&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_raw</span><span class="p">,</span>
            <span class="s2">&quot;path&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">,</span>
            <span class="s2">&quot;persons&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span><span class="p">,</span>
            <span class="s2">&quot;place&quot;</span><span class="p">:</span> <span class="n">place</span><span class="p">,</span>
            <span class="s2">&quot;portrait&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">portrait</span><span class="p">,</span>
            <span class="s2">&quot;raw_original&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">raw_original</span><span class="p">,</span>
            <span class="s2">&quot;score&quot;</span><span class="p">:</span> <span class="n">score</span><span class="p">,</span>
            <span class="s2">&quot;screenshot&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">screenshot</span><span class="p">,</span>
            <span class="s2">&quot;screen_recording&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">screen_recording</span><span class="p">,</span>
            <span class="s2">&quot;selfie&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">selfie</span><span class="p">,</span>
            <span class="s2">&quot;shared&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">shared</span><span class="p">,</span>
            <span class="s2">&quot;slow_mo&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">slow_mo</span><span class="p">,</span>
            <span class="s2">&quot;time_lapse&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">time_lapse</span><span class="p">,</span>
            <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
            <span class="s2">&quot;tzoffset&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">tzoffset</span><span class="p">,</span>
            <span class="s2">&quot;uti_edited&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti_edited</span><span class="p">,</span>
            <span class="s2">&quot;uti_original&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti_original</span><span class="p">,</span>
            <span class="s2">&quot;uti_raw&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti_raw</span><span class="p">,</span>
            <span class="s2">&quot;uti&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti</span><span class="p">,</span>
            <span class="s2">&quot;uuid&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">,</span>
            <span class="s2">&quot;visible&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">visible</span><span class="p">,</span>
            <span class="s2">&quot;width&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span><span class="p">,</span>
        <span class="p">}</span>

        <span class="c1"># non-shallow keys</span>
        <span class="c1"># add any new properties here</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">shallow</span><span class="p">:</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;album_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">album</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">album_info</span><span class="p">]</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;path_derivatives&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_derivatives</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;adjustments&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">adjustments</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">adjustments</span> <span class="k">else</span> <span class="p">{}</span>
            <span class="p">)</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;burst_album_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst_album_info</span><span class="p">]</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;burst_albums&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst_albums</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;burst_default_pick&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst_default_pick</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;burst_key&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst_key</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;burst_photos&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">uuid</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst_photos</span><span class="p">]</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;burst_selected&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst_selected</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;cloud_metadata&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cloud_metadata</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;import_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">import_info</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">import_info</span> <span class="k">else</span> <span class="p">{}</span>
            <span class="p">)</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;labels_normalized&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">labels_normalized</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;person_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">person_info</span><span class="p">]</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;project_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">project_info</span><span class="p">]</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;search_info&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">search_info</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">search_info</span> <span class="k">else</span> <span class="p">{}</span>
            <span class="p">)</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;search_info_normalized&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">search_info_normalized</span><span class="o">.</span><span class="n">asdict</span><span class="p">()</span>
                <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">search_info_normalized</span>
                <span class="k">else</span> <span class="p">{}</span>
            <span class="p">)</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;syndicated&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">syndicated</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;saved_to_library&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">saved_to_library</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;shared_moment&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">shared_moment</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;shared_library&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">shared_library</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;rating&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">rating</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;screen_recording&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">screen_recording</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;date_original&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">date_original</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;tzname&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">tzname</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;media_analysis&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">media_analysis</span>
            <span class="n">dict_data</span><span class="p">[</span><span class="s2">&quot;ai_caption&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">ai_caption</span>

        <span class="k">return</span> <span class="n">dict_data</span></div>


<div class="viewcode-block" id="iPhotoPhotoInfo.json">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPhotoInfo.json">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">indent</span><span class="p">:</span> <span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">shallow</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return JSON representation</span>

<span class="sd">        Args:</span>
<span class="sd">            indent: indent level for JSON, if None, no indent</span>
<span class="sd">            shallow: if True, return shallow JSON representation (does not contain folder_info, person_info, etc.)</span>

<span class="sd">        Returns:</span>
<span class="sd">            JSON string</span>

<span class="sd">        Note:</span>
<span class="sd">            The shallow representation is used internally by export as it contains only the subset of data needed for export.</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="k">def</span><span class="w"> </span><span class="nf">default</span><span class="p">(</span><span class="n">o</span><span class="p">):</span>
            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">,</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">)):</span>
                <span class="k">return</span> <span class="n">o</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>

        <span class="n">dict_data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">(</span><span class="n">shallow</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="k">if</span> <span class="n">shallow</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">(</span><span class="n">shallow</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>

        <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">dict_data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="c1"># sort lists such as keywords so JSON is consistent</span>
            <span class="c1"># but do not sort certain items like location</span>
            <span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;location&quot;</span><span class="p">]:</span>
                <span class="k">continue</span>
            <span class="k">if</span> <span class="n">v</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">))</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nb">dict</span><span class="p">):</span>
                <span class="n">dict_data</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">v</span> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">dict_data</span><span class="p">,</span> <span class="n">sort_keys</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">default</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="n">indent</span><span class="p">)</span></div>


    <span class="k">def</span><span class="w"> </span><span class="nf">_json_hexdigest</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;JSON for use by hexdigest()&quot;&quot;&quot;</span>

        <span class="c1"># This differs from json() because hexdigest must not change if metadata changed</span>
        <span class="c1"># With json(), sort order of lists of dicts is not consistent but these aren&#39;t needed</span>
        <span class="c1"># for computing hexdigest so we can ignore them</span>
        <span class="c1"># also don&#39;t use visible because it changes based on Photos UI state</span>

        <span class="k">def</span><span class="w"> </span><span class="nf">default</span><span class="p">(</span><span class="n">o</span><span class="p">):</span>
            <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">date</span><span class="p">,</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">)):</span>
                <span class="k">return</span> <span class="n">o</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>

        <span class="n">dict_data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">(</span><span class="n">shallow</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

        <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;face_info&quot;</span><span class="p">,</span> <span class="s2">&quot;visible&quot;</span><span class="p">]:</span>
            <span class="k">del</span> <span class="n">dict_data</span><span class="p">[</span><span class="n">k</span><span class="p">]</span>

        <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">dict_data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="c1"># sort lists such as keywords so JSON is consistent</span>
            <span class="c1"># but do not sort certain items like location</span>
            <span class="k">if</span> <span class="n">k</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;location&quot;</span><span class="p">]:</span>
                <span class="k">continue</span>
            <span class="k">if</span> <span class="n">v</span> <span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">))</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nb">dict</span><span class="p">):</span>
                <span class="n">dict_data</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">v</span><span class="p">:</span> <span class="n">v</span> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">dict_data</span><span class="p">,</span> <span class="n">sort_keys</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">default</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_get_faces</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get faces for photo&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;edited_faces&quot;</span><span class="p">,</span> <span class="p">[])</span>
            <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span>
            <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;faces&quot;</span><span class="p">,</span> <span class="p">[])</span>
        <span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;osxphotos.</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">(db=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="si">}</span><span class="s2">, uuid=&#39;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_uuid</span><span class="si">}</span><span class="s2">&#39;, info=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_info</span><span class="si">}</span><span class="s2">)&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;string representation of iPhotoPhotoInfo object&quot;&quot;&quot;</span>

        <span class="n">date_iso</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
        <span class="n">date_modified_iso</span> <span class="o">=</span> <span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">date_modified</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">date_modified</span> <span class="k">else</span> <span class="kc">None</span>
        <span class="p">)</span>
        <span class="n">exif</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">exif_info</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">exif_info</span> <span class="k">else</span> <span class="kc">None</span>
        <span class="n">score</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">score</span><span class="p">)</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">score</span> <span class="k">else</span> <span class="kc">None</span>

        <span class="n">info</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s2">&quot;uuid&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">,</span>
            <span class="s2">&quot;filename&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">,</span>
            <span class="s2">&quot;original_filename&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_filename</span><span class="p">,</span>
            <span class="s2">&quot;date&quot;</span><span class="p">:</span> <span class="n">date_iso</span><span class="p">,</span>
            <span class="s2">&quot;description&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">description</span><span class="p">,</span>
            <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
            <span class="s2">&quot;keywords&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span><span class="p">,</span>
            <span class="s2">&quot;albums&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">albums</span><span class="p">,</span>
            <span class="s2">&quot;persons&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">persons</span><span class="p">,</span>
            <span class="s2">&quot;path&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">,</span>
            <span class="s2">&quot;ismissing&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">ismissing</span><span class="p">,</span>
            <span class="s2">&quot;hasadjustments&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">,</span>
            <span class="s2">&quot;external_edit&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">external_edit</span><span class="p">,</span>
            <span class="s2">&quot;favorite&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">favorite</span><span class="p">,</span>
            <span class="s2">&quot;hidden&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">hidden</span><span class="p">,</span>
            <span class="s2">&quot;latitude&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_latitude</span><span class="p">,</span>
            <span class="s2">&quot;longitude&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_longitude</span><span class="p">,</span>
            <span class="s2">&quot;path_edited&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_edited</span><span class="p">,</span>
            <span class="s2">&quot;shared&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">shared</span><span class="p">,</span>
            <span class="s2">&quot;isphoto&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">isphoto</span><span class="p">,</span>
            <span class="s2">&quot;ismovie&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">ismovie</span><span class="p">,</span>
            <span class="s2">&quot;uti&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti</span><span class="p">,</span>
            <span class="s2">&quot;burst&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">burst</span><span class="p">,</span>
            <span class="s2">&quot;live_photo&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">live_photo</span><span class="p">,</span>
            <span class="s2">&quot;path_live_photo&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_live_photo</span><span class="p">,</span>
            <span class="s2">&quot;iscloudasset&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">iscloudasset</span><span class="p">,</span>
            <span class="s2">&quot;incloud&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">incloud</span><span class="p">,</span>
            <span class="s2">&quot;date_modified&quot;</span><span class="p">:</span> <span class="n">date_modified_iso</span><span class="p">,</span>
            <span class="s2">&quot;portrait&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">portrait</span><span class="p">,</span>
            <span class="s2">&quot;screenshot&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">screenshot</span><span class="p">,</span>
            <span class="s2">&quot;screen_recording&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">screen_recording</span><span class="p">,</span>
            <span class="s2">&quot;slow_mo&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">slow_mo</span><span class="p">,</span>
            <span class="s2">&quot;time_lapse&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">time_lapse</span><span class="p">,</span>
            <span class="s2">&quot;hdr&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">hdr</span><span class="p">,</span>
            <span class="s2">&quot;selfie&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">selfie</span><span class="p">,</span>
            <span class="s2">&quot;panorama&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">panorama</span><span class="p">,</span>
            <span class="s2">&quot;has_raw&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">has_raw</span><span class="p">,</span>
            <span class="s2">&quot;uti_raw&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uti_raw</span><span class="p">,</span>
            <span class="s2">&quot;path_raw&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">path_raw</span><span class="p">,</span>
            <span class="s2">&quot;place&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">place</span><span class="p">,</span>
            <span class="s2">&quot;exif&quot;</span><span class="p">:</span> <span class="n">exif</span><span class="p">,</span>
            <span class="s2">&quot;score&quot;</span><span class="p">:</span> <span class="n">score</span><span class="p">,</span>
            <span class="s2">&quot;intrash&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">intrash</span><span class="p">,</span>
            <span class="s2">&quot;height&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">height</span><span class="p">,</span>
            <span class="s2">&quot;width&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">width</span><span class="p">,</span>
            <span class="s2">&quot;orientation&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">orientation</span><span class="p">,</span>
            <span class="s2">&quot;original_height&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_height</span><span class="p">,</span>
            <span class="s2">&quot;original_width&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_width</span><span class="p">,</span>
            <span class="s2">&quot;original_orientation&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_orientation</span><span class="p">,</span>
            <span class="s2">&quot;original_filesize&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">original_filesize</span><span class="p">,</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="n">yaml</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">info</span><span class="p">,</span> <span class="n">sort_keys</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__getattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;If attribute is not found in iPhotoPhotoInfo, look at PhotoInfo and return default type&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_attributes</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid attribute: </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Returning default value for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">; not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">default_return_value</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_attributes</span><span class="p">[</span><span class="n">name</span><span class="p">])</span>
        <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
            <span class="c1"># on &lt;= Python 3.9, default_return_value can raise exception for Union types</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s2">&quot;Error getting default value for </span><span class="si">{name}</span><span class="s2">: </span><span class="si">{e}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="k">return</span> <span class="kc">None</span></div>



<div class="viewcode-block" id="iPhotoPersonInfo">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPersonInfo">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoPersonInfo</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;PersonInfo implementation for iPhoto&quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">face</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">db</span><span class="p">:</span> <span class="n">iPhotoDB</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_face</span> <span class="o">=</span> <span class="n">face</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db</span>

        <span class="n">face_key</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]</span>
        <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_persons</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">face_key</span> <span class="o">==</span> <span class="n">person</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_person</span> <span class="o">=</span> <span class="n">person</span>
                <span class="k">break</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Didn&#39;t find person for face </span><span class="si">{</span><span class="n">face_key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_person</span> <span class="o">=</span> <span class="p">{}</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;UUID of person&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_person</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;uuid&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">name</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Name of person&quot;&quot;&quot;</span>
        <span class="c1"># self._person[&quot;name&quot;] could be None</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_person</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">_UNKNOWN_PERSON</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">keyphoto</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoPhotoInfo</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Key photo for person&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">keyface</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoFaceInfo</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Key face for person&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">photos</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoPhotoInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;List of photos face is contained in&quot;&quot;&quot;</span>
        <span class="n">photos</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="p">:</span>
            <span class="n">photos</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span>
                <span class="n">iPhotoPhotoInfo</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;faces&quot;</span><span class="p">]</span>
                <span class="k">if</span> <span class="n">face</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]</span>
            <span class="p">)</span>
        <span class="k">return</span> <span class="n">photos</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">facecount</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Count of faces for person&quot;&quot;&quot;</span>
        <span class="n">faces</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="k">for</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">for</span> <span class="n">face</span> <span class="ow">in</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;faces&quot;</span><span class="p">]:</span>
                <span class="k">if</span> <span class="n">face</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]:</span>
                    <span class="n">faces</span> <span class="o">+=</span> <span class="mi">1</span>
        <span class="k">return</span> <span class="n">faces</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">favorite</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns False for iPhoto&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">False</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">sort_order</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Always returns 0 for iPhoto&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="mi">0</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">feature_less</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Always returns False for iPhoto&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">False</span>

<div class="viewcode-block" id="iPhotoPersonInfo.asdict">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPersonInfo.asdict">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return person as dict&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">{</span>
            <span class="s2">&quot;uuid&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">,</span>
            <span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
            <span class="s2">&quot;displayname&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
            <span class="s2">&quot;keyface&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">keyface</span><span class="p">,</span>
            <span class="s2">&quot;facecount&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">facecount</span><span class="p">,</span>
            <span class="s2">&quot;keyphoto&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">keyphoto</span><span class="p">,</span>
            <span class="s2">&quot;favorite&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">favorite</span><span class="p">,</span>
            <span class="s2">&quot;sort_order&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">sort_order</span><span class="p">,</span>
            <span class="s2">&quot;feature_less&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">feature_less</span><span class="p">,</span>
        <span class="p">}</span></div>


<div class="viewcode-block" id="iPhotoPersonInfo.json">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoPersonInfo.json">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return person as json&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">())</span></div>
</div>



<div class="viewcode-block" id="iPhotoFaceInfo">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoFaceInfo">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoFaceInfo</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;FaceInfo implementation for iPhoto&quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">photo</span><span class="p">:</span> <span class="n">iPhotoPhotoInfo</span><span class="p">,</span> <span class="n">face</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">db</span><span class="p">:</span> <span class="n">iPhotoDB</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_face</span> <span class="o">=</span> <span class="n">face</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">photo</span> <span class="o">=</span> <span class="n">photo</span>

        <span class="n">face_key</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]</span>
        <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_persons</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">face_key</span> <span class="o">==</span> <span class="n">person</span><span class="p">[</span><span class="s2">&quot;face_key&quot;</span><span class="p">]:</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">_person</span> <span class="o">=</span> <span class="n">person</span>
                <span class="k">break</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Didn&#39;t find person for face </span><span class="si">{</span><span class="n">face_key</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_person</span> <span class="o">=</span> <span class="p">{}</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">name</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Name of person in the photo or None&quot;&quot;&quot;</span>
        <span class="c1"># self._person[&quot;name&quot;] could be None</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_person</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">_UNKNOWN_PERSON</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">center</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Coordinates, in PIL format, for center of face</span>

<span class="sd">        Returns:</span>
<span class="sd">            tuple of coordinates in form (x, y)</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_make_point</span><span class="p">((</span><span class="bp">self</span><span class="o">.</span><span class="n">center_x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">center_y</span><span class="p">))</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">center_x</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;X coordinate for center of face as percent of width&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;topLeftX&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;width&quot;</span><span class="p">]</span> <span class="o">/</span> <span class="mi">2</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">center_y</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Y coordinate for center of face as percent of height&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;orientation&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;portrait&quot;</span><span class="p">:</span>
            <span class="c1"># y coords are reversed for portraits</span>
            <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;bottomRightY&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;height&quot;</span><span class="p">]</span> <span class="o">/</span> <span class="mi">2</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;topLeftY&quot;</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;height&quot;</span><span class="p">]</span> <span class="o">/</span> <span class="mi">2</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">quality</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Quality (confidence) of face detection&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;confidence&quot;</span><span class="p">]</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">_make_point</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">xy</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Translate an (x, y) tuple based on image orientation</span>
<span class="sd">            and convert to image coordinates</span>

<span class="sd">        Arguments:</span>
<span class="sd">            xy: tuple of (x, y) coordinates for point to translate</span>
<span class="sd">                in format used by Photos (percent of height/width)</span>

<span class="sd">        Returns:</span>
<span class="sd">            (x, y) tuple of translated coordinates in pixels in PIL format/reference frame</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">xy</span>

        <span class="n">photo</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span>
        <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">:</span>
            <span class="c1"># edited version</span>
            <span class="n">dx</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">width</span>
            <span class="n">dy</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">height</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># original version</span>
            <span class="n">dx</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">original_width</span>
            <span class="n">dy</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">original_height</span>
        <span class="k">return</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">x</span> <span class="o">*</span> <span class="n">dx</span><span class="p">),</span> <span class="nb">int</span><span class="p">(</span><span class="n">y</span> <span class="o">*</span> <span class="n">dy</span><span class="p">))</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">size</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Size of face as percent of image width&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;width&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">size_pixels</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Size of face in pixels (centered around center_x, center_y)</span>

<span class="sd">        Returns:</span>
<span class="sd">            size, in int pixels, of a circle drawn around the center of the face</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">width</span> <span class="o">=</span> <span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">width</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">hasadjustments</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">original_width</span>
        <span class="p">)</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;width&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">width</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">person_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoPersonInfo</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;iPhotoPersonInfo object for face&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">iPhotoPersonInfo</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>

<div class="viewcode-block" id="iPhotoFaceInfo.roll_pitch_yaw">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoFaceInfo.roll_pitch_yaw">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">roll_pitch_yaw</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Roll, pitch, yaw of face in radians as tuple&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span></div>


    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">roll</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return roll angle in radians of the face region&quot;&quot;&quot;</span>
        <span class="n">roll</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll_pitch_yaw</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">roll</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">pitch</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return pitch angle in radians of the face region&quot;&quot;&quot;</span>
        <span class="n">_</span><span class="p">,</span> <span class="n">pitch</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll_pitch_yaw</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">pitch</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">yaw</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return yaw angle in radians of the face region&quot;&quot;&quot;</span>
        <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">yaw</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">roll_pitch_yaw</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">yaw</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">mwg_rs_area</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">MWG_RS_Area</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get coordinates for Metadata Working Group Region Area.</span>

<span class="sd">        Returns:</span>
<span class="sd">            MWG_RS_Area named tuple with x, y, h, w where:</span>
<span class="sd">            x = stArea:x</span>
<span class="sd">            y = stArea:y</span>
<span class="sd">            h = stArea:h</span>
<span class="sd">            w = stArea:w</span>

<span class="sd">        Reference:</span>
<span class="sd">            https://photo.stackexchange.com/questions/106410/how-does-xmp-define-the-face-region</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">center_x</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">center_y</span>
        <span class="n">w</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;width&quot;</span><span class="p">]</span>
        <span class="n">h</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;height&quot;</span><span class="p">]</span>

        <span class="k">return</span> <span class="n">MWG_RS_Area</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="n">w</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">mpri_reg_rect</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">MPRI_Reg_Rect</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get coordinates for Microsoft Photo Region Rectangle.</span>

<span class="sd">        Returns:</span>
<span class="sd">            MPRI_Reg_Rect named tuple with x, y, h, w where:</span>
<span class="sd">            x = x coordinate of top left corner of rectangle</span>
<span class="sd">            y = y coordinate of top left corner of rectangle</span>
<span class="sd">            h = height of rectangle</span>
<span class="sd">            w = width of rectangle</span>

<span class="sd">        Reference:</span>
<span class="sd">            https://docs.microsoft.com/en-us/windows/win32/wic/-wic-people-tagging</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="c1"># x, y = self.center_x, self.center_y</span>

        <span class="n">photo</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span>
        <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">:</span>
            <span class="c1"># edited version</span>
            <span class="n">image_width</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">width</span>
            <span class="n">image_height</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">height</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># original version</span>
            <span class="n">image_width</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">original_width</span>
            <span class="n">image_height</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">original_height</span>

        <span class="n">h</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">size_pixels</span> <span class="o">/</span> <span class="n">image_width</span>
        <span class="n">w</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">size_pixels</span> <span class="o">/</span> <span class="n">image_height</span>
        <span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;topLeftX&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_width</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;orientation&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;portrait&quot;</span><span class="p">:</span>
            <span class="c1"># y coords are reversed for portraits</span>
            <span class="n">y</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;bottomRightY&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_height</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">y</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;topLeftY&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_height</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">MPRI_Reg_Rect</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="n">w</span><span class="p">)</span>

<div class="viewcode-block" id="iPhotoFaceInfo.face_rect">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoFaceInfo.face_rect">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">face_rect</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Get face rectangle coordinates for current version of the associated image</span>
<span class="sd">            If image has been edited, rectangle applies to edited version, otherwise original version</span>
<span class="sd">            Coordinates in format and reference frame used by PIL</span>

<span class="sd">        Returns:</span>
<span class="sd">            list [(x0, x1), (y0, y1)] of coordinates in reference frame used by PIL</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">photo</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span>
        <span class="k">if</span> <span class="n">photo</span><span class="o">.</span><span class="n">hasadjustments</span><span class="p">:</span>
            <span class="c1"># edited version</span>
            <span class="n">image_width</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">width</span>
            <span class="n">image_height</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">height</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="c1"># original version</span>
            <span class="n">image_width</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">original_width</span>
            <span class="n">image_height</span> <span class="o">=</span> <span class="n">photo</span><span class="o">.</span><span class="n">original_height</span>

        <span class="c1"># convert to PIL format</span>
        <span class="c1"># sourcery skip: hoist-statement-from-if</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">photo</span><span class="o">.</span><span class="n">_info</span><span class="p">[</span><span class="s2">&quot;orientation&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;portrait&quot;</span><span class="p">:</span>
            <span class="c1"># y coordinates are reversed</span>
            <span class="n">x0</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;topLeftX&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_width</span><span class="p">)</span>
            <span class="n">y0</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;bottomRightY&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_height</span><span class="p">)</span>
            <span class="n">x1</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;bottomRightX&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_width</span><span class="p">)</span>
            <span class="n">y1</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;topLeftY&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_height</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">x0</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;topLeftX&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_width</span><span class="p">)</span>
            <span class="n">y0</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;topLeftY&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_height</span><span class="p">)</span>
            <span class="n">x1</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;bottomRightX&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_width</span><span class="p">)</span>
            <span class="n">y1</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_face</span><span class="p">[</span><span class="s2">&quot;bottomRightY&quot;</span><span class="p">]</span> <span class="o">*</span> <span class="n">image_height</span><span class="p">)</span>
        <span class="k">return</span> <span class="p">[(</span><span class="n">x0</span><span class="p">,</span> <span class="n">y0</span><span class="p">),</span> <span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">)]</span></div>


<div class="viewcode-block" id="iPhotoFaceInfo.asdict">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoFaceInfo.asdict">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns dict representation of class instance&quot;&quot;&quot;</span>
        <span class="c1"># roll, pitch, yaw = self.roll_pitch_yaw()</span>
        <span class="k">return</span> <span class="p">{</span>
            <span class="c1"># &quot;uuid&quot;: self.uuid,</span>
            <span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
            <span class="s2">&quot;center_x&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">center_x</span><span class="p">,</span>
            <span class="s2">&quot;center_y&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">center_y</span><span class="p">,</span>
            <span class="s2">&quot;center&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">center</span><span class="p">,</span>
            <span class="s2">&quot;size&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="p">,</span>
            <span class="s2">&quot;face_rect&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">face_rect</span><span class="p">(),</span>
            <span class="s2">&quot;mpri_reg_rect&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">mpri_reg_rect</span><span class="o">.</span><span class="n">_asdict</span><span class="p">(),</span>
            <span class="s2">&quot;mwg_rs_area&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">mwg_rs_area</span><span class="o">.</span><span class="n">_asdict</span><span class="p">(),</span>
            <span class="s2">&quot;quality&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">quality</span><span class="p">,</span>
            <span class="c1"># &quot;source_width&quot;: self.source_width,</span>
            <span class="c1"># &quot;source_height&quot;: self.source_height,</span>
        <span class="p">}</span></div>


<div class="viewcode-block" id="iPhotoFaceInfo.json">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoFaceInfo.json">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return JSON representation of iPhotoFaceInfo instance&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">())</span></div>
</div>



<div class="viewcode-block" id="iPhotoAlbumInfo">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoAlbumInfo">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoAlbumInfo</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;AlbumInfo class for iPhoto&quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">album</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">db</span><span class="p">:</span> <span class="n">iPhotoDB</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_album</span> <span class="o">=</span> <span class="n">album</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_album_id</span> <span class="o">=</span> <span class="n">album</span><span class="p">[</span><span class="s2">&quot;albumId&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;UUID of album&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album</span><span class="p">[</span><span class="s2">&quot;album_uuid&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">title</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Title of album&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">photos</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoPhotoInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of photos contained in the album&quot;&quot;&quot;</span>
        <span class="n">photos</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">uuid</span><span class="p">,</span> <span class="n">photo</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
            <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">photo</span><span class="p">[</span><span class="s2">&quot;albums&quot;</span><span class="p">]:</span>
                <span class="k">if</span> <span class="n">album</span><span class="p">[</span><span class="s2">&quot;albumId&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album_id</span><span class="p">:</span>
                    <span class="n">photos</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">iPhotoPhotoInfo</span><span class="p">(</span><span class="n">uuid</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">))</span>
                    <span class="k">break</span>
        <span class="k">return</span> <span class="n">photos</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">folder_names</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return hierarchical list of folders the album is contained in</span>
<span class="sd">        the folder list is in form:</span>
<span class="sd">        [&quot;Top level folder&quot;, &quot;sub folder 1&quot;, &quot;sub folder 2&quot;, ...]</span>
<span class="sd">        or empty list if album is not in any folders</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">path</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album</span><span class="p">[</span><span class="s2">&quot;path&quot;</span><span class="p">]</span>
        <span class="k">if</span> <span class="n">path</span><span class="p">:</span>
            <span class="n">path</span> <span class="o">=</span> <span class="n">path</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>  <span class="c1"># remove album name from end of path</span>
        <span class="k">return</span> <span class="n">path</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">folder_list</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoFolderInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns hierachical list of iPhotoFolderInfo objects for each folder the album is contained in</span>
<span class="sd">        or empty list if album is not in any folders</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">folder_list</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="n">parent</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">parent</span>
        <span class="k">while</span> <span class="n">parent</span><span class="p">:</span>
            <span class="n">folder_list</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">parent</span><span class="p">)</span>
            <span class="n">parent</span> <span class="o">=</span> <span class="n">parent</span><span class="o">.</span><span class="n">parent</span>
        <span class="k">return</span> <span class="n">folder_list</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">parent</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoFolderInfo</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns iPhotoFolderInfo object for parent folder or None if no parent (e.g. top-level album)&quot;&quot;&quot;</span>
        <span class="n">parent_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_album</span><span class="p">[</span><span class="s2">&quot;folder_id&quot;</span><span class="p">]</span>
        <span class="n">parent_folder</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_folders</span><span class="p">[</span><span class="n">parent_id</span><span class="p">]</span>
        <span class="k">if</span> <span class="nb">bool</span><span class="p">(</span><span class="n">parent_folder</span><span class="p">[</span><span class="s2">&quot;isMagic&quot;</span><span class="p">]):</span>
            <span class="k">return</span> <span class="kc">None</span>
        <span class="k">return</span> <span class="n">iPhotoFolderInfo</span><span class="p">(</span><span class="n">parent_folder</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">sort_order</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return sort order; not implemented, always 0&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="mi">0</span>

<div class="viewcode-block" id="iPhotoAlbumInfo.photo_index">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoAlbumInfo.photo_index">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">photo_index</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">photo</span><span class="p">:</span> <span class="n">iPhotoPhotoInfo</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return index of photo in album; not implemented, always 0&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="mi">0</span></div>


<div class="viewcode-block" id="iPhotoAlbumInfo.asdict">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoAlbumInfo.asdict">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return album info as a dict; does not include photos&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">{</span>
            <span class="s2">&quot;uuid&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">,</span>
            <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
            <span class="s2">&quot;folder_names&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">folder_names</span><span class="p">,</span>
            <span class="s2">&quot;folder_list&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">uuid</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">folder_list</span><span class="p">],</span>
            <span class="s2">&quot;sort_order&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">sort_order</span><span class="p">,</span>
            <span class="s2">&quot;parent&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">uuid</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">parent</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
        <span class="p">}</span></div>


<div class="viewcode-block" id="iPhotoAlbumInfo.json">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoAlbumInfo.json">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;JSON representation of album&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">())</span></div>


    <span class="k">def</span><span class="w"> </span><span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;return number of photos contained in album&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">photos</span><span class="p">)</span></div>



<div class="viewcode-block" id="iPhotoFolderInfo">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoFolderInfo">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoFolderInfo</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">    Info about a specific folder, contains all the details about the folder</span>
<span class="sd">    including folders, albums, etc</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">folder</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">db</span><span class="p">:</span> <span class="n">iPhotoDB</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_folder</span> <span class="o">=</span> <span class="n">folder</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_folderid</span> <span class="o">=</span> <span class="n">folder</span><span class="p">[</span><span class="s2">&quot;modelId&quot;</span><span class="p">]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">title</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Title of folder&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_folder</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">uuid</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;UUID of folder&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_folder</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">album_info</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoAlbumInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of albums (as iPhotoAlbumInfo objects) contained in the folder&quot;&quot;&quot;</span>
        <span class="n">folder_albums</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">albums</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_albums</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="n">folder_albums</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span>
                <span class="n">iPhotoAlbumInfo</span><span class="p">(</span><span class="n">album</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
                <span class="k">for</span> <span class="n">album</span> <span class="ow">in</span> <span class="n">albums</span>
                <span class="k">if</span> <span class="n">album</span><span class="p">[</span><span class="s2">&quot;folder_id&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">_folderid</span>
            <span class="p">)</span>
        <span class="k">return</span> <span class="n">folder_albums</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">parent</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">iPhotoFolderInfo</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return iPhotoFolderInfo object for parent or None if no parent (e.g. top-level folder)&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="n">parent_uuid</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_folder</span><span class="p">[</span><span class="s2">&quot;parentFolderUuid&quot;</span><span class="p">]:</span>
            <span class="k">return</span> <span class="nb">next</span><span class="p">(</span>
                <span class="p">(</span>
                    <span class="p">(</span>
                        <span class="kc">None</span>
                        <span class="k">if</span> <span class="nb">bool</span><span class="p">(</span><span class="n">folder</span><span class="p">[</span><span class="s2">&quot;isMagic&quot;</span><span class="p">])</span>
                        <span class="k">else</span> <span class="n">iPhotoFolderInfo</span><span class="p">(</span><span class="n">folder</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span>
                    <span class="p">)</span>
                    <span class="k">for</span> <span class="n">folder</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_folders</span><span class="o">.</span><span class="n">values</span><span class="p">()</span>
                    <span class="k">if</span> <span class="n">folder</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">parent_uuid</span>
                <span class="p">),</span>
                <span class="kc">None</span><span class="p">,</span>
            <span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">subfolders</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoFolderInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return list of folders (as FolderInfo objects) contained in the folder&quot;&quot;&quot;</span>
        <span class="n">subfolders</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">folder</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_folders</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
            <span class="k">if</span> <span class="n">folder</span><span class="p">[</span><span class="s2">&quot;parentFolderUuid&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">:</span>
                <span class="k">if</span> <span class="nb">bool</span><span class="p">(</span><span class="n">folder</span><span class="p">[</span><span class="s2">&quot;isMagic&quot;</span><span class="p">]):</span>
                    <span class="c1"># skip magic folders like &quot;TopLevelAlbums&quot;</span>
                    <span class="k">continue</span>
                <span class="n">subfolders</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">iPhotoFolderInfo</span><span class="p">(</span><span class="n">folder</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">subfolders</span>

<div class="viewcode-block" id="iPhotoFolderInfo.asdict">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoFolderInfo.asdict">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return folder info as a dict&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">{</span>
            <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
            <span class="s2">&quot;uuid&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">uuid</span><span class="p">,</span>
            <span class="s2">&quot;parent&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">parent</span><span class="o">.</span><span class="n">uuid</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">parent</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
            <span class="s2">&quot;subfolders&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">uuid</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">subfolders</span><span class="p">],</span>
            <span class="s2">&quot;albums&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">a</span><span class="o">.</span><span class="n">uuid</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">album_info</span><span class="p">],</span>
        <span class="p">}</span></div>


<div class="viewcode-block" id="iPhotoFolderInfo.json">
<a class="viewcode-back" href="../../reference.html#osxphotos.iPhotoFolderInfo.json">[docs]</a>
    <span class="k">def</span><span class="w"> </span><span class="nf">json</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return folder info as json&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">asdict</span><span class="p">())</span></div>


    <span class="k">def</span><span class="w"> </span><span class="fm">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;returns count of folders + albums contained in the folder&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">subfolders</span><span class="p">)</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">album_info</span><span class="p">)</span></div>



<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoEventInfo</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;iPhoto Event info&quot;&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">],</span> <span class="n">db</span><span class="p">:</span> <span class="n">iPhotoDB</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_event</span> <span class="o">=</span> <span class="n">event</span>
        <span class="c1"># self._folderid = folder[&quot;modelId&quot;]</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">db</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">pk</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Primary key of the event.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;modelId&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">location</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Location of the event.&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">title</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Title of the event.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">))</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">subtitle</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Subtitle of the event.&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="s2">&quot;&quot;</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">start_date</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Start date of the event.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">iphoto_date_to_datetime</span><span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="p">[</span><span class="s2">&quot;min_image_date&quot;</span><span class="p">],</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="p">[</span><span class="s2">&quot;min_image_tz&quot;</span><span class="p">],</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">end_date</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Stop date of the event.&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="n">iphoto_date_to_datetime</span><span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="p">[</span><span class="s2">&quot;max_image_date&quot;</span><span class="p">],</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="p">[</span><span class="s2">&quot;max_image_tz&quot;</span><span class="p">],</span>
        <span class="p">)</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">date</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Date of the event.&quot;&quot;&quot;</span>
        <span class="c1"># use end_date as iPhoto doesn&#39;t record a separate date</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">end_date</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">_date_created</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Date the event created in iPhoto.&quot;&quot;&quot;</span>
        <span class="c1"># not common with Photos MomentInfo so leave private</span>
        <span class="k">return</span> <span class="n">photos_datetime_local</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="p">[</span><span class="s2">&quot;date&quot;</span><span class="p">])</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">modification_date</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Modification date of the event.&quot;&quot;&quot;</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Not implemented for iPhoto&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="kc">None</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">photos</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">iPhotoPhotoInfo</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;All photos in this moment&quot;&quot;&quot;</span>
        <span class="n">roll</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;modelId&quot;</span><span class="p">)</span>
        <span class="n">photos</span> <span class="o">=</span> <span class="p">[</span><span class="n">p</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_photos</span><span class="o">.</span><span class="n">values</span><span class="p">()</span> <span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;roll&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="n">roll</span><span class="p">]</span>
        <span class="k">return</span> <span class="p">[</span><span class="n">iPhotoPhotoInfo</span><span class="p">(</span><span class="n">p</span><span class="p">[</span><span class="s2">&quot;uuid&quot;</span><span class="p">],</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="p">)</span> <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">photos</span><span class="p">]</span>

    <span class="nd">@property</span>
    <span class="k">def</span><span class="w"> </span><span class="nf">note</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Return note associated with event&quot;&quot;&quot;</span>
        <span class="n">roll</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_event</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;modelId&quot;</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">note</span> <span class="o">:=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_db</span><span class="o">.</span><span class="n">_db_event_notes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">roll</span><span class="p">):</span>
            <span class="k">return</span> <span class="n">note</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;note&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="s2">&quot;&quot;</span>

    <span class="k">def</span><span class="w"> </span><span class="nf">asdict</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">        </span><span class="sd">&quot;&quot;&quot;Returns all moment info as dictionary&quot;&quot;&quot;</span>
        <span class="k">return</span> <span class="p">{</span>
            <span class="s2">&quot;pk&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
            <span class="s2">&quot;location&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="p">,</span>
            <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
            <span class="s2">&quot;subtitle&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">subtitle</span><span class="p">,</span>
            <span class="s2">&quot;start_date&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">start_date</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">start_date</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
            <span class="s2">&quot;end_date&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">end_date</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">end_date</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
            <span class="s2">&quot;date&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">date</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">date</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
            <span class="s2">&quot;modification_date&quot;</span><span class="p">:</span> <span class="p">(</span>
                <span class="bp">self</span><span class="o">.</span><span class="n">modification_date</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">modification_date</span> <span class="k">else</span> <span class="kc">None</span>
            <span class="p">),</span>
            <span class="s2">&quot;note&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">note</span><span class="p">,</span>
            <span class="c1"># &quot;photos&quot;: self.photos,</span>
        <span class="p">}</span>


<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoMomentInfo</span><span class="p">(</span><span class="n">iPhotoEventInfo</span><span class="p">):</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Info about a photo moment; iPhoto doesn&#39;t have moments but Events are close&quot;&quot;&quot;</span>

    <span class="o">...</span>


<span class="nd">@dataclasses</span><span class="o">.</span><span class="n">dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">class</span><span class="w"> </span><span class="nc">iPhotoExifInfo</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;EXIF info associated with a photo from the iPhoto library&quot;&quot;&quot;</span>

    <span class="n">flash_fired</span><span class="p">:</span> <span class="nb">bool</span>
    <span class="n">iso</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">metering_mode</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">sample_rate</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">track_format</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">white_balance</span><span class="p">:</span> <span class="nb">int</span>
    <span class="n">aperture</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">bit_rate</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">duration</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">exposure_bias</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">focal_length</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">fps</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">latitude</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">longitude</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">shutter_speed</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">camera_make</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">camera_model</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">codec</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">lens_model</span><span class="p">:</span> <span class="nb">str</span>
    <span class="n">software</span><span class="p">:</span> <span class="nb">str</span>
    <span class="nb">dict</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span>


<span class="c1">### Utility functions ###</span>


<span class="k">def</span><span class="w"> </span><span class="nf">default_return_value</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Inspect name and return default value if there is one otherwise None</span>
<span class="sd">    optimized for PhotoInfo may not work for other classes.</span>

<span class="sd">    If used to inspect a method or function that uses &#39;|&#39; to indicate a UnionType,</span>
<span class="sd">    requires Python 3.10 or greater because get_type_hints will fail on union types</span>
<span class="sd">    in earlier versions of Python.</span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="nb">property</span><span class="p">):</span>
        <span class="n">hints</span> <span class="o">=</span> <span class="n">get_type_hints</span><span class="p">(</span><span class="n">name</span><span class="o">.</span><span class="n">fget</span><span class="p">)</span>
    <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">functools</span><span class="o">.</span><span class="n">cached_property</span><span class="p">):</span>
        <span class="n">hints</span> <span class="o">=</span> <span class="n">get_type_hints</span><span class="p">(</span><span class="n">name</span><span class="o">.</span><span class="n">func</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">hints</span> <span class="o">=</span> <span class="n">get_type_hints</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
    <span class="n">return_type</span> <span class="o">=</span> <span class="n">hints</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;return&quot;</span><span class="p">)</span>

    <span class="c1"># inspect return_type and take best guess at default value</span>
    <span class="c1"># needs to run on Python 3.9 so can&#39;t depend on types.UnionType (3.10)</span>
    <span class="n">return_type</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">return_type</span><span class="p">)</span>
    <span class="k">if</span> <span class="s2">&quot;| None&quot;</span> <span class="ow">in</span> <span class="n">return_type</span><span class="p">:</span>
        <span class="k">return</span> <span class="kc">None</span>
    <span class="k">elif</span> <span class="n">return_type</span> <span class="o">==</span> <span class="nb">str</span><span class="p">(</span><span class="nb">bool</span><span class="p">):</span>
        <span class="k">return</span> <span class="kc">False</span>
    <span class="k">elif</span> <span class="n">return_type</span> <span class="o">==</span> <span class="nb">str</span><span class="p">(</span><span class="nb">str</span><span class="p">):</span>
        <span class="k">return</span> <span class="s2">&quot;&quot;</span>
    <span class="k">elif</span> <span class="n">return_type</span> <span class="o">==</span> <span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">):</span>
        <span class="k">return</span> <span class="mi">0</span>
    <span class="k">elif</span> <span class="n">return_type</span> <span class="o">==</span> <span class="nb">str</span><span class="p">(</span><span class="nb">float</span><span class="p">):</span>
        <span class="k">return</span> <span class="mf">0.0</span>
    <span class="k">elif</span> <span class="n">return_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;list[&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">return_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;List[&quot;</span><span class="p">):</span>
        <span class="k">return</span> <span class="p">[]</span>
    <span class="k">elif</span> <span class="s2">&quot;tuple[None, None]&quot;</span> <span class="ow">in</span> <span class="n">return_type</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
    <span class="k">elif</span> <span class="n">return_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;tuple[&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">return_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;Tuple[&quot;</span><span class="p">):</span>
        <span class="k">return</span> <span class="p">()</span>
    <span class="k">elif</span> <span class="n">return_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;dict[&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">return_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;Dict[&quot;</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">dict</span><span class="p">()</span>
    <span class="k">elif</span> <span class="n">return_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;set[&quot;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">return_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;Set[&quot;</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">set</span><span class="p">()</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unknown return type: </span><span class="si">{</span><span class="n">return_type</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
    <span class="k">return</span> <span class="kc">None</span>


<span class="k">def</span><span class="w"> </span><span class="nf">get_user_attributes</span><span class="p">(</span><span class="bp">cls</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Get user attributes from a class&quot;&quot;&quot;</span>
    <span class="c1"># reference: https://stackoverflow.com/questions/4241171/inspect-python-class-attributes</span>
    <span class="n">builtin_attributes</span> <span class="o">=</span> <span class="nb">dir</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="s2">&quot;dummy&quot;</span><span class="p">,</span> <span class="p">(</span><span class="nb">object</span><span class="p">,),</span> <span class="p">{}))</span>
    <span class="n">attrs</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="n">bases</span> <span class="o">=</span> <span class="nb">reversed</span><span class="p">(</span><span class="n">inspect</span><span class="o">.</span><span class="n">getmro</span><span class="p">(</span><span class="bp">cls</span><span class="p">))</span>
    <span class="k">for</span> <span class="n">base</span> <span class="ow">in</span> <span class="n">bases</span><span class="p">:</span>
        <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="s2">&quot;__dict__&quot;</span><span class="p">):</span>
            <span class="n">attrs</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">base</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">)</span>
        <span class="k">elif</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="s2">&quot;__slots__&quot;</span><span class="p">):</span>
            <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">base</span><span class="o">.</span><span class="vm">__slots__</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span>
                <span class="c1"># We&#39;re dealing with a non-string sequence or one char string</span>
                <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">base</span><span class="o">.</span><span class="vm">__slots__</span><span class="p">:</span>
                    <span class="n">attrs</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">item</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="c1"># We&#39;re dealing with a single identifier as a string</span>
                <span class="n">attrs</span><span class="p">[</span><span class="n">base</span><span class="o">.</span><span class="vm">__slots__</span><span class="p">]</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">base</span><span class="o">.</span><span class="vm">__slots__</span><span class="p">)</span>
    <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">builtin_attributes</span><span class="p">:</span>
        <span class="k">del</span> <span class="n">attrs</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>  <span class="c1"># we can be sure it will be present so no need to guard this</span>
    <span class="k">return</span> <span class="n">attrs</span>


<span class="k">def</span><span class="w"> </span><span class="nf">is_iphoto_library</span><span class="p">(</span><span class="n">library</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span> <span class="o">|</span> <span class="n">os</span><span class="o">.</span><span class="n">PathLike</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="w">    </span><span class="sd">&quot;&quot;&quot;Return True if library is an iPhoto library, else False&quot;&quot;&quot;</span>
    <span class="n">library</span> <span class="o">=</span> <span class="n">library</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">library</span><span class="p">,</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">)</span> <span class="k">else</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">library</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">library</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span>
        <span class="k">return</span> <span class="kc">False</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">library</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;AlbumData.xml&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
        <span class="k">return</span> <span class="kc">False</span>
    <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="n">library</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s2">&quot;Database&quot;</span><span class="p">,</span> <span class="s2">&quot;Library.apdb&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">is_file</span><span class="p">())</span>
</pre></div>
        </article>
      </div>
      <footer>
        
        <div class="related-pages">
          
          
        </div>
        <div class="bottom-of-page">
          <div class="left-details">
            <div class="copyright">
                Copyright &#169; 2021, Rhet Turnbull
            </div>
            Made with <a href="https://www.sphinx-doc.org/">Sphinx</a> and <a class="muted-link" href="https://pradyunsg.me">@pradyunsg</a>'s
            
            <a href="https://github.com/pradyunsg/furo">Furo</a>
            
          </div>
          <div class="right-details">
            
          </div>
        </div>
        
      </footer>
    </div>
    <aside class="toc-drawer no-toc">
      
      
      
    </aside>
  </div>
</div><script src="../../_static/documentation_options.js?v=63568c49"></script>
    <script src="../../_static/doctools.js?v=9bcbadda"></script>
    <script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
    <script src="../../_static/scripts/furo.js?v=46bd48cc"></script>
    <script src="../../_static/clipboard.min.js?v=a7894cd8"></script>
    <script src="../../_static/copybutton.js?v=f281be69"></script>
    </body>
</html>